Integration Reference
BACK API Integration
One reference for the full round trip: push your orders into Back, receive webhook events as returns are processed, and confirm refunds once you settle them. Three touchpoints, one shared data model.
01Overview
Integrating with Back has three touchpoints, and they form a loop around a single order.
1 · You send orders to Back. The Import Orders API is the starting point — you push your order and product data so Back knows what exists and can later match a return to the right item.
2 · Back sends events to you. When a customer starts a return, Back grades it, runs your rules, and creates the return shipment — pushing a webhook event to your endpoint at each step. Every event reuses one payload shape, so you write one handler and branch on the event name.
3 · You confirm refunds to Back. When a refund is due, Back initiates it and you settle it on your store, then confirm back so Back can close the loop.
All three speak JSON. Outbound calls (import, refund confirm) go to https://live.api.back.tech; inbound webhooks arrive at the endpoint you register on the Back portal.
02Integration flow
From onboarding to a live round trip.
POST /api/order/add (up to 500 orders per request). This seeds Back with everything a return might reference. See Import orders.POST with a JSON body. It just needs to read the body, return 2xx quickly, and process asynchronously.Authorization: Bearer <token>. Leave it blank to skip auth. See Authentication.03Order lifecycle
Events fire in roughly this order. Each stage is where a part of the payload first becomes available.
Not every order takes the happy path — grading can be skipped (grade.skiped), and shipping or labels can fail (shipping.failed, shipping.label.failed).
04Import orders
The starting point for any integration. Send Back your order and product data so a return can later be matched to the right item.
Content-Type: application/json [ { /* order */ }, { /* order */ } ] // array, up to 500 orders
The body is an array of orders (max 500 per request). Each order carries the products purchased, the customer's address and contact, and order metadata such as payment mode and costs — the inputs Back's rule engine works from. Fields not documented here are generated server-side.
failed is null (or empty) and message states how many were imported. On partial or complete failure, failed is an array of items, each with a reason and the order that failed. A malformed payload that fails validation returns 400.YYYY-MM-DD in requests (responses may use ISO 8601 date-time). order_id, team_name and client_name are the reference names shared by the Back team during onboarding — send them exactly as given. Each field below is tagged required or optional — send every required field for the order to process correctly.Request body
▶[ ] ordersarray · max 500root
"USP001""UB83BY""vip-store""us-polo"▶addressobjectrequired
GB.▶contactobjectrequired
Date.toString())."201"Amazon. Empty accepted.YYYY-MM-DD. Empty / null accepted.FRAUD, POOR, FAIR, GOOD, VERY GOOD, EXCELLENT, VIP.▶paymentobjectrequired
GBP.FLAT, PERCENT.VOUCHER.payment_mode is OTHER.▶productsobject[]required
quantity. Back splits multi-quantity lines into individual units internally.1.high | normal. Default normal.true. Send false for items that may not be returned.YYYY-MM-DD. After this date the customer can't return the product.YYYY-MM-DD. Empty / null accepted.YYYY-MM-DD."delivered". Cannot be null.RETURN, EXCHANGE.▶shipping_detailsobjectrequired
▶dimensionsobjectoptional
1.1.1.▶insuranceobjectoptionalnullable
is_insured is true, insured_amount and insured_currency become required.false.is_insured is true; otherwise optional (defaults to 0).is_insured is true; otherwise optional (defaults to GBP).▶variantsobjectoptional
▶size[]object[]optional
{ "value": "STD", "label": "Standard" }.▶color[]object[]optional
{ "value": "BLK", "label": "Black" }.Example request
[
{
"order_id": "USP001",
"unique_code": "UB83BY",
"total_order_value": "201",
"team_name": "vip-store",
"client_name": "us-polo",
"order_date": "Mon Sep 10 2025 13:28:06 GMT+0100",
"platform_name": "Amazon",
"customer_score": "GOOD",
"lifetime_value": 100,
"first_order_date": "2025-08-05",
"address": {
"line_1": "56 Example Street",
"line_2": " ",
"state": "England",
"city": "London",
"postal_code": "E1 6JJ",
"country_alpha2": "GB"
},
"contact": {
"company_name": "Example Retail Ltd",
"first_name": "Alex",
"last_name": "Johnson",
"contact_phone": "+442079460000",
"contact_email": "alex.johnson@example.com"
},
"payment": {
"currency": "GBP",
"discount_code_type": "FLAT",
"free_delivery": false,
"order_value_for_free_delivery": 5,
"payment_mode": "VOUCHER"
},
"products": [
{
"team_name": "vip-store",
"name": "USB-C Fast Charger 25W",
"actual_price": 10,
"category_name": "Clothes, Shoes & Accessories",
"product_id": "REG52",
"variant_id": "REG52-BLK-STD",
"description": "USB-C fast charger, 25W",
"brand": "Nike",
"rrp": 15,
"cogs": 5,
"quantity": 1,
"priority": "high",
"return_allowed": true,
"return_by_date": "2025-08-31",
"purchased_date": "2025-08-10",
"delivery_date": "2025-08-12",
"delivery_status": "delivered",
"images": [ "https://cdn.example.com/products/charger-front.jpg" ],
"sku": "usb-c-fast-charger-25w",
"sku_color": "Black",
"sku_size": "STD",
"vat": 1,
"duty": 1,
"shipping_details": {
"origin_country_alpha2": "GB",
"actual_weight": 0.1,
"declared_currency": "GBP",
"declared_customs_value": "10",
"hs_code": "85044095",
"contains_battery_pi966": false,
"contains_battery_pi967": false,
"contains_liquids": false,
"dimensions": { "length": 5, "width": 1, "height": 1 },
"insurance": { "is_insured": false, "insured_amount": 0, "insured_currency": "GBP" }
},
"variants": {
"size": [ { "value": "STD", "label": "Standard" } ],
"color": [ { "value": "BLK", "label": "Black" } ]
},
"returnType": "RETURN"
}
]
}
]
Responses
HTTP 200 is always returned (except for a malformed payload, which returns 400). Inspect the envelope to determine the real outcome.
▶200 · import resultobject
"success".null when everything imported. Otherwise an array of failures, each with a reason (e.g. "Team or Client not found!!"), the echoed order that failed, and a server-generated batchUid.{ "success": true, "data": { "data": "success", "value": { "message": "1 Orders imported. Order are in queue. you'll receive the update through webhook.", "failed": null } }, "error": "" }
{ "success": true, "data": { "data": "success", "value": { "message": "0 Orders imported. Order are in queue. you'll receive the update through webhook.", "failed": [ { "reason": "Team or Client not found!!", "order": { /* the echoed order that failed */ }, "batchUid": "2880e8d2-163d-41c7-aebd-372baaca403b" } ] } }, "error": "" }
| Status | Meaning |
|---|---|
| 200 | Request processed. Check data.value.failed for per-item outcomes. |
| 400 | Invalid payload — failed schema (Joi) validation. Fix the body and resend. |
05Authentication optional
Webhooks are calls from Back to you. Bearer auth on them is optional — add it only if you want to verify the caller is Back.
When registering the webhook you may supply a secret token. If you do, Back attaches it to every delivery in the standard Authorization header; verify it before trusting the body and return 401 if it's missing or wrong. Leave the token blank and Back sends no Authorization header, so your endpoint should accept the call as-is. (Access for your outbound calls — Import Orders and Refund confirm — is provisioned by the Back team at onboarding.)
// Authorization is sent only if you configured a token. // The signature headers are sent whenever a token is configured. Authorization: Bearer <YOUR_WEBHOOK_TOKEN> X-8ack-Timestamp: <unix-ms> X-8ack-Signature: sha256=<hex-hmac> Content-Type: application/json { /* event payload — see Webhook payload */ }
Signature verification. Whenever a token is configured, Back also HMAC-signs every delivery so you can verify integrity and freshness. Compute HMAC-SHA256 over the string {X-8ack-Timestamp}.{raw request body} using your webhook token as the secret, hex-encode it, and compare it (constant-time) with the value of X-8ack-Signature after its sha256= prefix. Reject the request if it doesn't match, or if X-8ack-Timestamp is outside your allowed clock skew (replay protection).
2xx status, Back retries with exponential backoff (up to 5 attempts). The same event can therefore arrive more than once — make your handler idempotent and dedupe on the payload id. Return 2xx quickly and do heavy work asynchronously.06Events
The event name arrives alongside the payload. Branch your handler on it.
grade object (label, system grade, confidence) is now populated.refund, charges and deductionCharges become available.order.return.rule.complete.shipping_details object (carrier, shipping id, tracking codes) becomes available.shipping_details.shipping_details.shippingStatus (e.g. in transit, out for delivery, delivered). This can fire several times as the shipment progresses.shipping_details.shippingStatus reflects the cancellation.07Conditional objects
One payload shape is reused for every event, so several objects are absent or null until the matching step has run. Always null-check before reading them.
| Object | Available from | Until then |
|---|---|---|
| aiRuleData | Rule engine completes (order.return.rule.complete) | Absent — no rule has run yet |
| returnDetails.grade | Product is graded (order.return.graded) | Absent — and never appears if grading was skipped (grade.skiped) |
| returnDetails.refund | Rules complete | Absent |
| returnDetails.charges | Rules complete | Absent |
| returnDetails.deductionCharges | Rules complete. If the deduction rule is based on shipping, it is only populated once shipping is created. | Absent / zeroed |
| shipping_details | Shipping is created (shipping.created) | null |
| shipping_details · label URLs | Label is created (shipping.label.created) — label_url, label_path, qr_code_url, tracking_number | null even though the shipping object exists |
returnDetails.grade.label before the return is graded will throw — guard with a presence check first.08Webhook payload
The full envelope, sanitized. Identifiable and client-specific values are shown as {{PLACEHOLDERS}}. Expand any object to see its fields.
id.▶orderDetailsobjectroot
event, id and created_at.▶addressobject
{{ADDRESS_LINE_1}}{{ADDRESS_LINE_2}}GB.▶locationobject
Point.[longitude, latitude].▶contactobject
{{COMPANY_NAME}}{{CUSTOMER_NAME}}{{CUSTOMER_FIRST_NAME}}{{CUSTOMER_LAST_NAME}}{{CUSTOMER_PHONE_B64}} — base64 of the phone number.{{CUSTOMER_EMAIL_B64}} — base64 of the email.▶paymentobject
GBP.FLAT or percentage-based.VOUCHER, CARD.{{ORDER_ID}}{{CLIENT_NAME}}{{TEAM_NAME}}meesho.▶productDetailsobject
address, location, contact and payment (with product-level price fields), plus the fields below.▶paymentobject
_gbp twin.product.payment.actual_price_gbp.▶shipping_detailsobject
length, width, height in cm.is_insured, insured_amount, insured_currency.color and size arrays.▶aiRuleDataobjectconditional
returnDetails.aiRuleData.{{PRODUCT_ID}}{{CLIENT_ID}}{{BRAND}}category_name.{{ASSET_PATH}}.high / medium / low.product_meta is a JSON-encoded string of extra attributes.▶returnDetailsobject
order_id, team_name, client_name, product_id, original_product_id, priority).REQUIRED — controls whether steps can be skipped.caption, instruction, file_path, mime_type, plus a background-removed copy (bgremove_path, bgremove_provider). Paths shown as {{ASSET_PATH}}.["Too small"].RETURN, EXCHANGE.REFUND.COMPLETED.graded_by.user_alias identifies the grader (e.g. an AI grader).▶gradeobjectconditional
order.return.graded. Absent when grading is skipped.C.Poor.▶actionobject
ACCEPT.SEND_TO_WAREHOUSE, SEND_TO_PARTNER.address (may include country), contact (phone/email encrypted), location_title, location_type (e.g. WAREHOUSE, CHARITY). Identity values shown as {{WAREHOUSE_*}}.partnerName and partnerId of the disposition partner (e.g. a charity). Set when the action routes to a partner.carrier_id, carrier_name, carrier, auth_company, shippingCarrier.shippingClass_id, pickup_type (e.g. PICKUP), pickup_collection_date_enabled.▶aiRuleDataobjectconditional
order.return.rule.complete). Describes the matched rule and the grading flow it triggered.component (with mappingKey like product.payment.actual_price_gbp), an expression (GT, LT, EQ…) and a value.GRADING_FLOW → AI_FLOW.AI_FLOW.grade_label / grade_code to score ranges for AI_DETECTION, AI_OCR_VALUE, AI_COMPARISON and STAIN_CONFIDENCE (from–to).▶refundobjectconditional
refund_type you act on lives — see Refund handling.CASH or STORE_CREDIT — tells you how to settle with your customer.refrence.)PENDING → APPROVED.▶chargesobjectconditional
value, priceType (FLAT), priceOf (e.g. shippingCost).▶deductionChargesobjectconditional
shipping.created.return_state (e.g. SHIPPING_SUCCESS), orderStatus, orderStatusColor.feedback and feedbacks[].ip → {{CUSTOMER_IP}}, fingerprint → {{DEVICE_FINGERPRINT}}; plus browser, platform, screen, timezone, etc.action and offer — any incentive presented in place of a refund (action: "NA" when none).▶shipping_detailsobjectconditional
null until shipping.created. Label and QR fields inside stay null until shipping.label.created.▶labelobject
shipping.label.failed.mime_type, file_path, url of the printable label PDF.DPD.shippingStatus e.g. created.tracking_codes_ngrams is a search-index helper you can ignore.Example payload
A trimmed, sanitized envelope. The grade matrix and repeated objects are abbreviated; expand the schema above for the full field list.
{ "orderDetails": { "order_id": "{{ORDER_ID}}", "client_name": "{{CLIENT_NAME}}", "team_name": "{{TEAM_NAME}}", "platform_name": "meesho", "contact": { "contact_name": "{{CUSTOMER_NAME}}", "contact_phone": "{{CUSTOMER_PHONE_B64}}", // base64 "contact_email": "{{CUSTOMER_EMAIL_B64}}" // base64 }, "payment": { "currency": "GBP", "total_order_value_gbp": "187.00" }, "productDetails": { "product_id": "{{PRODUCT_ID}}", "name": "Sample product", "sku": "SAMPLE-SKU", "sku_color": "Black", "sku_size": "XL", "payment": { "actual_price_gbp": 187, "cogs_gbp": 130.9 }, "images": [ "{{ASSET_PATH}}/1.webp" ] }, "returnDetails": { "return_req_id": "YNUZBD3NC5", "returnType": "RETURN", "tags": [ [ "Too small" ] ], "grade_status": "COMPLETED", "grade": { "label": "C", "system_level_grade": "Poor", "grade_code": "CC" }, // after order.return.graded "refund": { "refund_type": "CASH", // CASH | STORE_CREDIT — act on this "refund_amount": 187, "currency": "GBP", "status": "PENDING", "refund_refrence": null }, "deductionCharges": { "deductionGbp": 0, "refundValue": 187 }, "action": { "status": "ACCEPT", "action": "SEND_TO_PARTNER", "partner": { "partnerName": "Charity Partner", "partnerId": "partner_123" }, "pickup_options": { "pickup_type": "PICKUP" } }, "collection_date": "2026-07-27T04:21:00.000Z" }, "shipping_details": { // null until shipping.created "shipping_id": "MV163509342", "shippingCarrier": "DPD", "shippingStatus": "created", "tracking_codes": [ "5420740800" ], "label_path": null // url appears after shipping.label.created } } }
09Refund handling
Back decides a refund is due and fires order.refund.initiated. The actual settlement happens on your store — then you tell us it's done.
Read returnDetails.refund.refund_type to know how to settle:
| refund_type | What you do |
|---|---|
| CASH | Refund money back to the customer's original payment method, for the amount in refund.refund_amount / currency. |
| STORE_CREDIT | Issue store credit / a voucher to the customer for the same amount instead of returning cash. |
order.refund.initiated. 2. Settle the refund on your store (cash or store credit). 3. Confirm back to Back with the call below, passing your settlement reference. We then mark the refund APPROVED.10Confirm a refund
After you've settled, call this endpoint so Back can close the refund. This is the one call that goes from you to Back.
curl --request POST \ --url https://live.api.back.tech/api/dashboard/webhook/refund \ --header 'Content-Type: application/json' \ --data '{ "order_id": "{{ORDER_ID}}", "product_id": "{{PRODUCT_ID}}", "refund": { "refund_type": "CASH", "status": "APPROVED", "refund_refrence": "{{YOUR_REFERENCE}}" } }'
| Field | Notes |
|---|---|
| order_id | The order from the webhook payload. |
| product_id | The product the refund applies to. |
| refund.refund_type | CASH or STORE_CREDIT — the type you actually settled. |
| refund.status | Set to APPROVED once the refund has been completed on your side. |
| refund.refrence | Your settlement reference, returned to Back for reconciliation. Note the field is spelled refund_refrence. |
refund_refrence (one "e" missing). Send it verbatim or the confirmation won't bind.BACK API Integration — order import, webhook handling, and refund confirmation. Sample data is sanitized; every identifiable and client-specific value is a placeholder.