Product returns data processing
Send your returned and canceled items to the Returns API, and Creatable adjusts your sales reporting and commissions to reflect them. Setup is optional, but it keeps tracked sales and the commissions paid on them accurate.
To enable returns processing you need:
- API access credentials, created in Account > API Configuration.
- A process on your side that pulls online returns from your ERP or commerce platform and sends them to the Returns API, on whatever schedule suits you.
How it works
Your system sends Creatable a list of items returned or canceled from recent online orders, and we subtract them from the original purchases in your sales reporting and commissions.
- Query your ERP or commerce platform. A process on your side pulls items from recent online transactions that were returned or canceled.
- Filter to online orders. Exclude in-store transactions. Creatable only tracks online sales, so in-store returns have no matching purchase.
- (Optional) Filter to qualified transactions. Ask the Analytics API which transaction IDs Creatable tracked, and send returns only for those. See Optional: send returns only for qualified transactions.
- Send the list to the Returns API. Post the rows as JSON or CSV to the returns endpoint.
- Creatable updates reporting and commissions. Each returned item is applied as a negative quantity against its original purchase, reducing the reported sale and any commission not yet paid on it.
Overlapping sends are safe. Rows we have already processed are recognized and ignored, so you don't need to track exactly what you sent before.
Set it up
Setup takes four steps, and you can test end to end before automating it.
- Get your API credentials. In the Creatable dashboard, go to Account > API Configuration and copy your API username and API key. The Returns API uses these with HTTP Basic authentication.
- Build the returns export. Write a query or report in your ERP or commerce platform that returns recent online returns and cancellations, with the columns listed below.
- Send a test request. Post a few rows to the endpoint using one of the examples. A 2XX response means the data was accepted.
- Automate it. Run the export and upload on a schedule that fits your business, using a cron job, scheduled task, or your integration platform.
Questions during setup? Contact your client success representative or support@creatable.com.
API reference
Send returns with a POST request to the returns endpoint, authenticated with your API username and key.
POST https://app.creatable.io/v2/api/analytics/ingest/returns
Authentication: HTTP Basic auth. Use your API username and API key from Account > API Configuration.
Request formats
| Content-Type | Body |
|---|---|
application/json |
A JSON array of return objects, one per returned item |
text/csv |
Delimited text. The first row must be a header with the column names |
multipart/form-data |
A file upload. The file's first row must be a header with the column names |
Query parameters
Use these to match the format your system exports. All are optional.
| Parameter | Values | Default |
|---|---|---|
delimiter |
tab, comma |
comma |
quote_char |
single_quote, double_quote, none |
double_quote |
escape_char |
single_quote, double_quote, backslash, none |
backslash |
For example, a tab-separated file uses ?delimiter=tab.
Responses
| Status | Meaning |
|---|---|
200 |
Accepted |
400 |
Bad request, such as a missing required column or bad credentials |
500 |
Server error. Retry later |
Error responses include a JSON body with a message property describing the problem:
{ "message": "Missing required column: product_id" }
Returns data columns
Each row is one returned item. The same column names are used as JSON keys or as CSV header names.
| Column | Required | Description |
|---|---|---|
transaction_id |
Yes | ID of the original order the item was purchased in |
timestamp |
Yes | Date and time the item was returned or canceled, in ISO 8601 format (for example 2026-09-28T14:05:00Z) |
product_id |
Yes | Parent ID of the product |
variant_id |
Yes | ID of the exact item returned (SKU). If your products have no variants, use the product_id |
quantity |
Yes | Number of units returned. Positive or negative values are both accepted and treated as the same amount |
product_title |
Yes | Title or short description of the item |
note |
No | Optional free-text note, such as a return reason |
Only send returns for online orders. In-store transactions aren't tracked by Creatable and can't be matched.
Sample CSV
Copy this as a starting template. It includes a product with variants, a product without variants (variant_id repeats product_id), a partial return sent in two rows, and a row without a note.
transaction_id,timestamp,product_id,variant_id,quantity,product_title,note
1234567,2026-09-28T14:05:00Z,SHIRT-100,SHIRT-100-BLU-M,2,"Classic Tee - Blue, M",Wrong size
1234567,2026-09-30T10:20:00Z,SHIRT-100,SHIRT-100-BLU-M,1,"Classic Tee - Blue, M",Wrong size
3987234,2026-09-29T09:12:30Z,MUG-200,MUG-200,1,Ceramic Mug,Arrived damaged
4410982,2026-09-29T16:45:10Z,JKT-310,JKT-310-BLK-L,1,"Rain Jacket - Black, L",Canceled before shipping
5521877,2026-09-30T08:03:55Z,SOCK-050,SOCK-050-GRY-OS,3,"Crew Socks - Grey, One Size",
How returns are processed
A return reduces a sale only when it matches an original purchase whose commission hasn't been paid yet.
- Matching: a return is identified by the combination of
transaction_id,timestamp,product_id, andvariant_id. - Duplicates are ignored: a row with the same four values as one already processed is skipped, so overlapping sends are safe.
- Paid commissions are final: if the commission on the original transaction has already been released (its release date has passed), the row is ignored.
- No more than was purchased: total returns for an item can't exceed the quantity bought. Rows past that limit are ignored.
- Partial returns add up: an item bought in a quantity above one can be returned in several rows over time, up to the purchased total. For example, if a customer bought 5 blue shirts, you could send a return of 2 and later a return of 3, but not a further return after that.
- Quantity sign doesn't matter:
-2and2both mean two units returned.
Examples
Each example sends the same two returns. Replace API_USERNAME and API_KEY with your credentials from Account > API Configuration.
JSON
curl -X POST 'https://app.creatable.io/v2/api/analytics/ingest/returns' \
-u 'API_USERNAME:API_KEY' \
-H 'Content-Type: application/json' \
-d '[
{
"transaction_id": "1234567",
"timestamp": "2026-09-28T14:05:00Z",
"product_id": "SHIRT-100",
"variant_id": "SHIRT-100-BLU-M",
"quantity": 2,
"product_title": "Classic Tee - Blue, M",
"note": "Wrong size"
},
{
"transaction_id": "3987234",
"timestamp": "2026-09-29T09:12:30Z",
"product_id": "MUG-200",
"variant_id": "MUG-200",
"quantity": 1,
"product_title": "Ceramic Mug"
}
]'
CSV in the request body
curl -X POST 'https://app.creatable.io/v2/api/analytics/ingest/returns' \
-u 'API_USERNAME:API_KEY' \
-H 'Content-Type: text/csv' \
--data-binary @returns.csv
Where returns.csv contains:
transaction_id,timestamp,product_id,variant_id,quantity,product_title,note
1234567,2026-09-28T14:05:00Z,SHIRT-100,SHIRT-100-BLU-M,2,"Classic Tee - Blue, M",Wrong size
3987234,2026-09-29T09:12:30Z,MUG-200,MUG-200,1,Ceramic Mug,
File upload (tab-separated)
curl -X POST 'https://app.creatable.io/v2/api/analytics/ingest/returns?delimiter=tab' \
-u 'API_USERNAME:API_KEY' \
-F 'file=@returns.tsv'
curl -F sets the multipart/form-data content type for you.
Optional: send returns only for qualified transactions
Instead of sending every return, you can ask the Analytics API which transactions Creatable tracked and send returns for only those orders. This keeps payloads small and avoids sending data for orders that aren't in your Creatable reporting.
The Analytics API is a GraphQL API that uses the same credentials as the Returns API. Your account's endpoint URL is shown in Account > API Configuration and looks like this:
https://app.creatable.io/v2/api/analytics/brand/graphql/v1/YOUR_ACCOUNT_HASH
See Analytics API: getting started for more on the API.
Step 1: Get qualified transaction IDs
The transaction_report query lists the transactions Creatable tracked in a date range. Use a range that covers the original purchase dates of the returns you're about to send.
{
transaction_report(start_date: "2026-09-01", end_date: "2026-09-30", page: 1, per_page: 100) {
total
items {
transaction_id
transaction_date
}
}
}
curl -X POST 'https://app.creatable.io/v2/api/analytics/brand/graphql/v1/YOUR_ACCOUNT_HASH' \
-u 'API_USERNAME:API_KEY' \
-H 'Content-Type: application/json' \
-d '{"query":"{ transaction_report(start_date: \"2026-09-01\", end_date: \"2026-09-30\", page: 1, per_page: 100) { total items { transaction_id transaction_date } } }"}'
Results return up to 100 items per page. Use total to work out how many pages to request, and stay under the API's limit of 10 requests per second.
Step 2: Filter your returns and send them
From your returns export, keep only rows whose transaction_id appears in the list from step 1. Then send those rows to the Returns API as shown in the Examples section above.
Troubleshooting
I got a 4XX response. Read the message in the response body. Common causes are a missing required column, a header row that doesn't match the column names, a delimiter that doesn't match your file, or incorrect credentials.
I got a 5XX response. Something went wrong on our side. Retry the request later. Because duplicate rows are ignored, resending the same data is safe.
My request succeeded but a return isn't reflected in reporting. The row was likely skipped by one of the processing rules: the commission was already paid, the return exceeded the quantity purchased, the row was a duplicate, or the transaction wasn't tracked by Creatable (for example, an in-store order).
Can I send cancellations as well as returns? Yes. Send canceled items the same way as returned items. You can use the note column to record which it was.
Still stuck? Contact your client success representative or support@creatable.com.