API Reference

Integrate external systems with ReturnMate using the External API — offline repairs and trade returns with API-key authentication.

5 min read
Last updated 14 July 2026

ReturnMate's External API lets your own systems create and manage two kinds of RMAs: offline repairs (items handed in outside the customer portal — for example from a POS, service desk or partner system) and trade returns (B2B returns). It is not a general-purpose RMA API — the admin app and customer portal cover those workflows.

Base URL

https://api.returnmate.io/api/v1/external/v1

All endpoints below are relative to this base.

Authentication

Every request must include your API key in the X-Api-Key header (a Bearer token in the Authorization header is also accepted):

curl https://api.returnmate.io/api/v1/external/v1/offline-repairs \
  -H "X-Api-Key: rm_ext_YOUR_API_KEY"

Creating an API client

API clients are managed by an Admin in Settings → External API:

  1. Click Create API Client and enter a Client name and optional Webhook URL.
  2. The API Client Created dialog shows your API key (prefixed rm_ext_) and webhook secret once. Store both securely — ReturnMate keeps only a SHA-256 hash of the key and cannot show it again.
  3. Clients can be edited (name, webhook URL) or revoked at any time. Revoked keys stop working immediately.
Keys are shown once

If a key is lost or exposed, revoke the client and create a new one. There is no key-reveal or rotation endpoint.

Rate limiting

Creation endpoints (POST /offline-repairs, POST /trade-returns) are limited to 60 requests per minute (burst 5/second) per client IP. Other endpoints use the platform default (200 requests per minute). There are no plan-based rate tiers. Exceeding a limit returns 429 Too Many Requests.

Scale plan required — and plan limits still apply

The External API (and webhooks) is available on the Scale and Enterprise plans. On other plans every request returns 403 with code PLAN_REQUIRED. RMAs created through the API also count toward your plan's monthly RMA allowance: at the limit, creation fails with 403 and code LIMIT_EXCEEDED (or USAGE_CAP_EXCEEDED on a usage-billed plan). See Plans, Billing & Usage Limits.

Offline repairs

Create an offline repair

POST /offline-repairs

{
  "orderNumber": "1001",
  "customerEmail": "customer@example.com",
  "customerName": "Alex Chen",
  "customerPhone": "+61 400 000 000",
  "faultyItem": {
    "sku": "PWR-500",
    "productName": "Power Station 500",
    "quantity": 1,
    "price": 799.0,
    "serialNumber": "SN-1234",
    "variantTitle": "Black",
    "weight": 6.5
  },
  "faultDescription": "Unit will not charge past 20%",
  "storeId": "store_abc123",
  "externalRef": "TICKET-4821",
  "externalSource": "my-pos",
  "startStatus": "OFFLINE_DIAGNOSTICS",
  "replacementSku": "PWR-500",
  "notes": "Swapped over the counter",
  "tracking": { "trackingNumber": "ST123456", "carrierName": "StarTrack" }
}

Required fields: orderNumber, customerEmail, customerName, faultyItem (with sku, productName, quantity, price), faultDescription, storeId. startStatus must be COUNTER_SWAPPED or OFFLINE_DIAGNOSTICS if provided. externalRef/externalSource are your identifiers, echoed back in responses and webhooks.

Returns 201 Created with the RMA:

{
  "id": "cln_…",
  "rmaNumber": "#WAR1234A",
  "status": "OFFLINE_DIAGNOSTICS",
  "externalRef": "TICKET-4821",
  "externalSource": "my-pos",
  "orderNumber": "1001",
  "customerEmail": "customer@example.com",
  "customerName": "Alex Chen",
  "faultDescription": "Unit will not charge past 20%",
  "offlineDisposition": null,
  "isDangerous": false,
  "trackingNumber": null
}

Retrieve and list

  • GET /offline-repairs/:id — fetch one repair.
  • GET /offline-repairs?page=1&limit=20&status=OFFLINE_REPAIR&externalRef=…&externalSource=… — paginated list. The response contains items, total, page, limit and totalPages.
  • GET /offline-repairs/:id/timeline — the RMA's activity timeline entries.

Lifecycle actions

EndpointBodyEffect
POST /offline-repairs/:id/tracking{ "trackingNumber", "carrierName" }Lodge return postage tracking
POST /offline-repairs/:id/begin-diagnostics{ "notes?" }Move to Offline Diagnostics
POST /offline-repairs/:id/begin-repair{ "repairNotes?", "assignedToId?" }Move to Offline Repair
POST /offline-repairs/:id/resolve{ "offlineDisposition", "notes?" }Set disposition and resolve
POST /offline-repairs/:id/closeClose the repair

Dispositions follow the offline repair workflow: restock at master, restock at child, write off, or return to supplier. See Offline Repair Workflow.

Trade returns

For B2B (TradeMate) orders:

  • POST /trade-returns — create a trade return. Required: tradeOrderNumber, customerEmail, customerName, companyName, companyId, reason, items[] (each with sku, productName, quantity, price) and shippingAddress (street, suburb, state, postcode). Optional: customerPhone, orderDate, customerNotes, faultDescription, additionalComment, per-item variantTitle/weight/tradeLineItemId.
  • GET /trade-returns/:id — fetch one trade return.
  • GET /trade-returns — list trade returns.

Errors

Standard HTTP status codes with a JSON body:

StatusMeaning
400Validation failed — the message array lists field errors
401Missing or invalid X-Api-Key
403Plan restriction (PLAN_REQUIRED — API needs Scale+; LIMIT_EXCEEDED / USAGE_CAP_EXCEEDED — monthly RMA cap; READ_ONLY — subscription inactive)
404RMA not found for your shop
429Rate limit exceeded

Webhooks

If your API client has a Webhook URL configured, ReturnMate sends signed event notifications (offline_repair.*, trade_return.*) as the RMA progresses. See the Webhooks Reference.

Notes and limitations

  • There are no official SDKs; use any HTTP client.
  • There is no sandbox environment — test against a development store.
  • The API does not expose standard portal-created returns, labels, refunds or analytics.
Was this helpful?
Contact Support