Contents
CommerceBetaVersion v1

Returns Portal API

Let shoppers find their order and create a return, exchange or store-credit request.

The public API behind the Nucleo-hosted returns page (https://app.nucleoplatform.com/returns/{slug}). Use it to build your own returns experience inside your storefront or app: identify the order with its number plus the shopper's email or postcode, show what can be returned and how, create the return (refund, exchange with live stock, or store credit; carrier label or in-store drop-off; up to three photos), then follow it on a status page and download the return label.

There are no API keys. The shopper proves ownership with order number + email or postcode and gets a short-lived encrypted session token (X-Return-Session, one hour, one order). Each created return gets a long random return token that opens its status page and label without any session.

Every rule applied here (return window, non-returnable items, reasons, fees, exchange options) is the merchant's return policy, the same one used by customer service and the warehouse.

Authentication

  • returnSessionAPI key · header · X-Return-Session

    Session token returned by POST /lookup (data.session). Encrypted and signed by Nucleo, bound to the store and one order, valid 60 minutes; not renewable — look the order up again when it expires.

Base URL
https://api-commerce.nucleoplatform.com/api/oms/v1/public/returns/{slug}Production
Who calls it
Storefronts
Endpoints
6
OpenAPI 3.1 specification
returns.yaml
{slug} — The store's returns-portal slug (^[a-z0-9][a-z0-9-]{0,63}$). It is the last segment of the portal link shown in Settings › Orders › Returns and refunds › Return portal (https://app.nucleoplatform.com/returns/{slug}). (examples use acme; full URL https://api-commerce.nucleoplatform.com/api/oms/v1/public/returns/acme)

Portal

Branding and rules shown before the shopper signs in.

Turning it on. In Nucleo go to Settings › Orders › Returns and refunds › Return portal, switch the portal on and copy its link; the Return policy tab sets window, reasons, resolutions, fees and exclusions. While the portal is off, every endpoint that needs it answers 404 as if the store did not exist (return status pages and labels keep working).

get/

Get portal branding and rules

Brand (name, logo, accent colour, support contacts), languages, how the shopper can identify the order (verify_with), the default return window, the return fee and which resolutions are offered. Use it to render the sign-in step.

Rate limit: 60 requests per minute per client (bucket shared with /order, /r/{token} and /r/{token}/label), and 1,800 per minute for the whole store.

GET https://api-commerce.nucleoplatform.com/api/oms/v1/public/returns/acme/
Authentication: None — public endpoint
Rate limit: 60 requests per 1m, per IP

Responses

  • 200Portal information.
    • dataPortalInforequired
      Child attributes
      • brandBrandrequired
        Child attributes
        • namestringrequired
          Example: Acme Apparel
        • logo_urlstring (uri) | nullrequired
        • accent_colorstring | nullrequired
          Example: #0F766E
        • support_emailstring (email) | nullrequired
        • support_urlstring (uri) | nullrequired
        • slugstringrequired
          Example: acme
      • languagesarray of stringrequired
        One ofitendefres
      • default_languagestringrequired
        One ofitendefres
      • verify_witharray of stringrequired

        What the shopper may give besides the order number.

        One ofemailzip
      • window_daysintegerrequired

        Default return window in days from delivery (per-country/channel windows may differ; see order.returnable_until).

        Example: 30
      • feenumberrequired

        Return fee withheld from refunds, in the order currency (0 = free).

        Example: 4.9
      • resolutionsResolutionsrequired

        Which outcomes the shopper may choose.

        Child attributes
        • refundbooleanrequired
        • exchangebooleanrequired
        • store_creditbooleanrequired
  • 404The store does not exist or its returns portal is switched off. The body is an empty message. A slug that does not match ^[a-z0-9][a-z0-9-]{0,63}$ gets the generic route-not-found message.
    • messagestringrequired
  • 429Rate limit exceeded. No Retry-After header; wait retry_after seconds.
    • messagestringrequired
      One oftoo_many_requeststoo_many_attempts
    • retry_afterintegerrequired

      Seconds until the limit resets.

Request
curl -X GET https://api-commerce.nucleoplatform.com/api/oms/v1/public/returns/acme/ \
  -H 'Accept: application/json'
Response
{
  "data": {
    "brand": {
      "name": "Acme Apparel",
      "logo_url": "https://cdn.acme.example/logo.svg",
      "accent_color": "#0F766E",
      "support_email": "help@example.com",
      "support_url": "https://shop.acme.example/pages/contact",
      "slug": "acme"
    },
    "languages": [
      "it",
      "en",
      "de",
      "fr",
      "es"
    ],
    "default_language": "en",
    "verify_with": [
      "email",
      "zip"
    ],
    "window_days": 30,
    "fee": 4.9,
    "resolutions": {
      "refund": true,
      "exchange": true,
      "store_credit": true
    }
  }
}

Order lookup

Identify the order and open a one-hour session.

Building your own UI. The API can be called from the browser (CORS allows any origin and the X-Return-Session header) or from your server. Rate limits are counted per caller IP and the first address in X-Forwarded-For: if you proxy calls through your own server, forward the shopper's IP in X-Forwarded-For, otherwise all your shoppers share one bucket. Responses for "order not found" and "wrong email/postcode" are identical on purpose.

post/lookup

Find an order and open a session

Finds the order by number (with or without the leading #, case-insensitive) and checks the verifier against the order's email (case-insensitive) or shipping postcode (spaces and hyphens ignored), as allowed by the policy's verify_with. Exchange orders created by Nucleo cannot be looked up.

On success returns a session token valid for one hour for this order only, the resolved language and the full order view (what can be returned, reasons, resolutions, methods, fees, previous returns).

Language is the first of: language in the body, the order's language, the policy default — each only if enabled in the policy — otherwise en.

Rate limits

  • 10 lookups per minute per client (300 per minute for the whole store);
  • 5 failed attempts per order number every 15 minutes: after that the order number is locked (429 too_many_attempts) until the window expires. A successful lookup resets the counter.

Validation errors (422) do not count towards the limits.

POST https://api-commerce.nucleoplatform.com/api/oms/v1/public/returns/acme/lookup
Authentication: None — public endpoint
Rate limit: 10 requests per 1m, per IP

Request bodyapplication/json

  • orderstringrequired

    Order number, with or without #.

    max length 40
    Example: #1042
  • verifierstringrequired

    The email used for the order or the shipping postcode (whichever the policy allows).

    max length 120
    Example: giulia.rossi@example.com
  • languagestring | null

    Preferred language (it, en, de, fr, es); ignored if not enabled.

    max length 5
    Example: it

Responses

  • 200Order found; session opened.
    • dataobject & OrderViewrequired
      Child attributes
      • sessionstringrequired

        Opaque session token. Send it as X-Return-Session to /order and /returns.

      • expires_inintegerrequired

        Seconds until the session expires (always 3600).

        Example: 3600
      • languagestringrequired
        One ofitendefres
      • orderobjectrequired
        Child attributes
        • namestringrequired
          Example: #1042
        • placed_atstring (date-time) | nullrequired
        • delivered_atstring (date-time) | nullrequired
        • currencystringrequired
          Example: EUR
        • countrystring | nullrequired

          Shipping country.

          Example: IT
        • returnable_untilstring (date-time) | nullrequired

          End of the return window (from delivery, or shipment + 3 days if delivery is unknown).

        • blockedstring | nullrequired

          Why the whole order cannot be returned (null = it can): cancelled, not_shipped, window_closed, limit_reached (the customer reached the policy's maximum returns per period).

          One ofcancellednot_shippedwindow_closedlimit_reachednull
        • languagestring | nullrequired

          Language the order was placed in.

      • linesarray of OrderLinerequired
        Attributes of each item
        • idstring (uuid)required

          Order line ID, to reference in lines[].id when creating the return.

        • titlestringrequired
          Example: Organic Cotton Tee
        • sizestring | nullrequired

          Parsed from SKUs shaped MODEL_COLOR_SIZE; null otherwise.

          Example: M
        • colorstring | nullrequired
          Example: BLK
        • skustring | nullrequired
          Example: TEE_BLK_M
        • image_urlstring (uri) | nullrequired

          Product image from the Nucleo Catalog.

        • pricenumberrequired

          Unit price paid, tax included.

          Example: 39
        • quantityintegerrequired

          Quantity ordered.

        • returnableintegerrequired

          Quantity that can still be returned (shipped minus already in non-cancelled returns).

        • blockedstring | nullrequired

          Why this line cannot be returned (null = it can). Either the order-level reason, or excluded_sku (non-returnable product), excluded_tag (order tagged as non-returnable), final_sale (discount above the policy threshold), not_shipped, already_returned.

          One ofcancellednot_shippedwindow_closedlimit_reachedexcluded_skuexcluded_tagfinal_salealready_returnednull
        • exchange_optionsarray of objectrequired

          Other sizes (and colours, if the policy allows) of the same model, same colour first. Empty when the line is blocked, exchanges are off, or the SKU is not shaped MODEL_COLOR_SIZE.

          Attributes of each item
          • barcodestringrequired

            Pass as exchange_barcode.

            Example: 8001234567892
          • sizestring | nullrequired
            Example: L
          • colorstring | nullrequired
            Example: BLK
          • same_colorbooleanrequired
          • pricenumberrequired

            Current price of the replacement.

          • in_stockbooleanrequired
          • image_urlstring (uri) | nullrequired
      • reasonsarray of objectrequired

        Active return reasons, labelled in the session language.

        Attributes of each item
        • codestringrequired

          Stable code (defaults: too_small, too_big, style, color, defective, wrong_item, not_as_described, changed_mind, other; merchants can add their own).

          Example: too_small
        • labelstringrequired
          Example: Too small
        • photostringrequired

          Whether a photo is asked for when this reason is chosen.

          One ofnoneoptionalrequired
      • resolutionsResolutionsrequired

        Which outcomes the shopper may choose.

        Child attributes
        • refundbooleanrequired
        • exchangebooleanrequired
        • store_creditbooleanrequired
      • store_credit_bonus_pctnumberrequired

        Extra percentage granted when choosing store credit instead of a refund.

        Example: 10
      • methodsobjectrequired
        Child attributes
        • carrier_labelbooleanrequired

          A prepaid carrier label can be generated.

        • store_dropoffbooleanrequired

          The items can be dropped off in one of stores.

        • storesarray of objectrequired

          Drop-off stores, those in the order's shipping country first.

          Attributes of each item
          • idstring (uuid)required

            Pass as store_id when creating a store_dropoff return.

          • namestringrequired
          • countrystring | nullrequired
          • addressstring | nullrequired
      • feeobjectrequired
        Child attributes
        • amountnumberrequired

          Return fee withheld from the refund.

        • free_for_exchangebooleanrequired
        • free_for_store_creditbooleanrequired
        • free_in_storebooleanrequired
        • free_reasonsarray of stringrequired

          Reason codes for which the return is free.

      • exchangeobjectrequired
        Child attributes
        • upchargestringrequired

          If the replacement costs more, the shopper pays the difference (invoice) or the merchant absorbs it up to absorb_max.

          One ofinvoiceabsorb
        • absorb_maxnumberrequired
        • downchargestringrequired

          If the replacement costs less, how the difference goes back to the shopper.

          One ofrefundstore_credit
      • returnsarray of objectrequired

        Previous returns of this order (cancelled ones excluded), newest first.

        Attributes of each item
        • namestringrequired
          Example: #1042-R1
        • statusstringrequired

          The return in the shopper's words: requested (created, not yet on its way), in_transit, received, checking (received, refund under manual review), completed, refunded, cancelled.

          One ofrequestedin_transitreceivedcheckingcompletedrefundedcancelled
        • tokenstring | nullrequired

          Return token for the status page.

        • created_atstring (date-time) | nullrequired
  • 404not_found: no such order, or the email/postcode does not match (indistinguishable on purpose). Also returned, with an empty message, when the store or its portal does not exist or is off.
    • messagestringrequired
  • 422Invalid request body.
    • messagestringrequired
    • errorsobjectrequired
  • 429Too many lookups from this client, or too many failed attempts on this order number.
    • messagestringrequired
      One oftoo_many_requeststoo_many_attempts
    • retry_afterintegerrequired

      Seconds until the limit resets.

Request
curl -X POST https://api-commerce.nucleoplatform.com/api/oms/v1/public/returns/acme/lookup \
  -H 'Content-Type: application/json' \
  -d '{
  "order": "#1042",
  "verifier": "giulia.rossi@example.com",
  "language": "it"
}'
Response
{
  "data": {
    "session": "eyJpdiI6IkxQb3Z6c2J0c0Z6V2Z6dz09IiwidmFsdWUiOiJ3c3l6Q2R0Wm1rRk9TVnlqK2c9PSIsIm1hYyI6IjhhM2YifQ==",
    "expires_in": 3600,
    "language": "it",
    "order": {
      "name": "#1042",
      "placed_at": "2026-09-20T10:12:00+00:00",
      "delivered_at": "2026-09-23T14:30:00+00:00",
      "currency": "EUR",
      "country": "IT",
      "returnable_until": "2026-10-23T23:59:59+00:00",
      "blocked": null,
      "language": "it"
    },
    "lines": [
      {
        "id": "9d3f6b1e-2a4c-4e8b-a1f0-6c2d8e4b7a10",
        "title": "Organic Cotton Tee",
        "size": "M",
        "color": "BLK",
        "sku": "TEE_BLK_M",
        "image_url": "https://cdn.acme.example/products/tee-blk.jpg",
        "price": 39,
        "quantity": 1,
        "returnable": 1,
        "blocked": null,
        "exchange_options": [
          {
            "barcode": "8001234567892",
            "size": "L",
            "color": "BLK",
            "same_color": true,
            "price": 39,
            "in_stock": true,
            "image_url": "https://cdn.acme.example/products/tee-blk.jpg"
          },
          {
            "barcode": "8001234567908",
            "size": "M",
            "color": "WHT",
            "same_color": false,
            "price": 39,
            "in_stock": false,
            "image_url": "https://cdn.acme.example/products/tee-wht.jpg"
          }
        ]
      }
    ],
    "reasons": [
      {
        "code": "too_small",
        "label": "Troppo piccolo",
        "photo": "none"
      },
      {
        "code": "defective",
        "label": "Difettoso o danneggiato",
        "photo": "required"
      }
    ],
    "resolutions": {
      "refund": true,
      "exchange": true,
      "store_credit": true
    },
    "store_credit_bonus_pct": 10,
    "methods": {
      "carrier_label": true,
      "store_dropoff": true,
      "stores": [
        {
          "id": "4b8e2c71-0f3a-4d59-9e6b-2a7c1d8f5e03",
          "name": "Acme Apparel Milano",
          "country": "IT",
          "address": "Via Roma 1, 20121 Milano"
        }
      ]
    },
    "fee": {
      "amount": 4.9,
      "free_for_exchange": true,
      "free_for_store_credit": true,
      "free_in_store": true,
      "free_reasons": [
        "defective",
        "wrong_item"
      ]
    },
    "exchange": {
      "upcharge": "invoice",
      "absorb_max": 0,
      "downcharge": "refund"
    },
    "returns": []
  }
}
get/order

Get the order of the current session

The same order view returned by /lookup, recomputed now (returnable quantities, exchange stock, previous returns), without opening a new session. Use it to refresh the form or switch language.

Rate limit: 60 requests per minute per client (shared portal bucket), 1,800 per minute per store.

GET https://api-commerce.nucleoplatform.com/api/oms/v1/public/returns/acme/order
Authentication: X-Return-Session header
Rate limit: 60 requests per 1m, per IP

Query parameters

  • languagestring

    Preferred language; used only if enabled in the policy (see /lookup).

    One ofitendefres
    Example: it

Responses

  • 200The order view.
    • dataobject & OrderViewrequired
      Child attributes
      • languagestringrequired
        One ofitendefres
      • orderobjectrequired
        Child attributes
        • namestringrequired
          Example: #1042
        • placed_atstring (date-time) | nullrequired
        • delivered_atstring (date-time) | nullrequired
        • currencystringrequired
          Example: EUR
        • countrystring | nullrequired

          Shipping country.

          Example: IT
        • returnable_untilstring (date-time) | nullrequired

          End of the return window (from delivery, or shipment + 3 days if delivery is unknown).

        • blockedstring | nullrequired

          Why the whole order cannot be returned (null = it can): cancelled, not_shipped, window_closed, limit_reached (the customer reached the policy's maximum returns per period).

          One ofcancellednot_shippedwindow_closedlimit_reachednull
        • languagestring | nullrequired

          Language the order was placed in.

      • linesarray of OrderLinerequired
        Attributes of each item
        • idstring (uuid)required

          Order line ID, to reference in lines[].id when creating the return.

        • titlestringrequired
          Example: Organic Cotton Tee
        • sizestring | nullrequired

          Parsed from SKUs shaped MODEL_COLOR_SIZE; null otherwise.

          Example: M
        • colorstring | nullrequired
          Example: BLK
        • skustring | nullrequired
          Example: TEE_BLK_M
        • image_urlstring (uri) | nullrequired

          Product image from the Nucleo Catalog.

        • pricenumberrequired

          Unit price paid, tax included.

          Example: 39
        • quantityintegerrequired

          Quantity ordered.

        • returnableintegerrequired

          Quantity that can still be returned (shipped minus already in non-cancelled returns).

        • blockedstring | nullrequired

          Why this line cannot be returned (null = it can). Either the order-level reason, or excluded_sku (non-returnable product), excluded_tag (order tagged as non-returnable), final_sale (discount above the policy threshold), not_shipped, already_returned.

          One ofcancellednot_shippedwindow_closedlimit_reachedexcluded_skuexcluded_tagfinal_salealready_returnednull
        • exchange_optionsarray of objectrequired

          Other sizes (and colours, if the policy allows) of the same model, same colour first. Empty when the line is blocked, exchanges are off, or the SKU is not shaped MODEL_COLOR_SIZE.

          Attributes of each item
          • barcodestringrequired

            Pass as exchange_barcode.

            Example: 8001234567892
          • sizestring | nullrequired
            Example: L
          • colorstring | nullrequired
            Example: BLK
          • same_colorbooleanrequired
          • pricenumberrequired

            Current price of the replacement.

          • in_stockbooleanrequired
          • image_urlstring (uri) | nullrequired
      • reasonsarray of objectrequired

        Active return reasons, labelled in the session language.

        Attributes of each item
        • codestringrequired

          Stable code (defaults: too_small, too_big, style, color, defective, wrong_item, not_as_described, changed_mind, other; merchants can add their own).

          Example: too_small
        • labelstringrequired
          Example: Too small
        • photostringrequired

          Whether a photo is asked for when this reason is chosen.

          One ofnoneoptionalrequired
      • resolutionsResolutionsrequired

        Which outcomes the shopper may choose.

        Child attributes
        • refundbooleanrequired
        • exchangebooleanrequired
        • store_creditbooleanrequired
      • store_credit_bonus_pctnumberrequired

        Extra percentage granted when choosing store credit instead of a refund.

        Example: 10
      • methodsobjectrequired
        Child attributes
        • carrier_labelbooleanrequired

          A prepaid carrier label can be generated.

        • store_dropoffbooleanrequired

          The items can be dropped off in one of stores.

        • storesarray of objectrequired

          Drop-off stores, those in the order's shipping country first.

          Attributes of each item
          • idstring (uuid)required

            Pass as store_id when creating a store_dropoff return.

          • namestringrequired
          • countrystring | nullrequired
          • addressstring | nullrequired
      • feeobjectrequired
        Child attributes
        • amountnumberrequired

          Return fee withheld from the refund.

        • free_for_exchangebooleanrequired
        • free_for_store_creditbooleanrequired
        • free_in_storebooleanrequired
        • free_reasonsarray of stringrequired

          Reason codes for which the return is free.

      • exchangeobjectrequired
        Child attributes
        • upchargestringrequired

          If the replacement costs more, the shopper pays the difference (invoice) or the merchant absorbs it up to absorb_max.

          One ofinvoiceabsorb
        • absorb_maxnumberrequired
        • downchargestringrequired

          If the replacement costs less, how the difference goes back to the shopper.

          One ofrefundstore_credit
      • returnsarray of objectrequired

        Previous returns of this order (cancelled ones excluded), newest first.

        Attributes of each item
        • namestringrequired
          Example: #1042-R1
        • statusstringrequired

          The return in the shopper's words: requested (created, not yet on its way), in_transit, received, checking (received, refund under manual review), completed, refunded, cancelled.

          One ofrequestedin_transitreceivedcheckingcompletedrefundedcancelled
        • tokenstring | nullrequired

          Return token for the status page.

        • created_atstring (date-time) | nullrequired
  • 401session_expired: missing, invalid or expired X-Return-Session, or a session of another store.
    • messagestringrequired
  • 404The store does not exist or its returns portal is switched off. The body is an empty message. A slug that does not match ^[a-z0-9][a-z0-9-]{0,63}$ gets the generic route-not-found message.
    • messagestringrequired
  • 429Rate limit exceeded. No Retry-After header; wait retry_after seconds.
    • messagestringrequired
      One oftoo_many_requeststoo_many_attempts
    • retry_afterintegerrequired

      Seconds until the limit resets.

Request
curl -X GET 'https://api-commerce.nucleoplatform.com/api/oms/v1/public/returns/acme/order?language=it' \
  -H "X-Return-Session: $NUCLEO_RETURN_SESSION" \
  -H 'Accept: application/json'
Response
{
  "data": {
    "language": "it",
    "order": {
      "name": "#1042",
      "placed_at": "2026-10-01T09:30:00Z",
      "delivered_at": "2026-10-01T09:30:00Z",
      "currency": "EUR",
      "country": "IT",
      "returnable_until": "2026-10-01T09:30:00Z",
      "blocked": "cancelled",
      "language": "string"
    },
    "lines": [
      {
        "id": "9b2f4c1e-5d7a-4e8b-9c3d-2a1f0e6b7c8d",
        "title": "Organic Cotton Tee",
        "size": "M",
        "color": "BLK",
        "sku": "TEE_BLK_M",
        "image_url": "https://shop.acme.example",
        "price": 39,
        "quantity": 1,
        "returnable": 1,
        "blocked": "cancelled",
        "exchange_options": [
          {
            "barcode": "8001234567892",
            "size": "L",
            "color": "BLK",
            "same_color": true,
            "price": 1.5,
            "in_stock": true,
            "image_url": "https://shop.acme.example"
          }
        ]
      }
    ],
    "reasons": [
      {
        "code": "too_small",
        "label": "Too small",
        "photo": "none"
      }
    ],
    "resolutions": {
      "refund": true,
      "exchange": true,
      "store_credit": true
    },
    "store_credit_bonus_pct": 10,
    "methods": {
      "carrier_label": true,
      "store_dropoff": true,
      "stores": [
        {
          "id": "9b2f4c1e-5d7a-4e8b-9c3d-2a1f0e6b7c8d",
          "name": "string",
          "country": "string",
          "address": "string"
        }
      ]
    },
    "fee": {
      "amount": 1.5,
      "free_for_exchange": true,
      "free_for_store_credit": true,
      "free_in_store": true,
      "free_reasons": [
        "string"
      ]
    },
    "exchange": {
      "upcharge": "invoice",
      "absorb_max": 1.5,
      "downcharge": "refund"
    },
    "returns": [
      {
        "name": "#1042-R1",
        "status": "requested",
        "token": "string",
        "created_at": "2026-10-01T09:30:00Z"
      }
    ]
  }
}

Returns

Create a return for the order of the current session.

post/returns

Create a return

Creates a return for the session's order. Send either JSON or multipart/form-data (needed for photos). The return itself goes in payload: a JSON object (JSON body) or a JSON-encoded string (multipart). A JSON body without the payload wrapper is accepted too.

Checks, in order (the first failure is returned as 422 with a code in message):

  • the order as a whole can be returned (cancelled, not_shipped, window_closed, limit_reached);
  • method is offered (invalid_method) and, for store_dropoff, store_id is one of the listed stores (invalid_store);
  • for each line: still returnable in that quantity (line_not_returnable), reason is an active reason (invalid_reason), resolution is enabled (invalid_resolution), and for exchange the chosen exchange_barcode is among the line's options and in stock for the quantity (exchange_unavailable);
  • at least one valid line (no_lines) — lines with an unknown id or a quantity of 0 are skipped;
  • at least one photo when a chosen reason requires it (photo_required).

What happens

  • A return {order}-R{n} is created in status requested, with the return fee computed by the policy (free for exchange/store credit, in-store drop-off or "our fault" reasons if so configured).
  • The return is routed to the location that will receive it.
  • Exchanges: a replacement order {order}-EX{n} is created and the new size/colour is reserved. In standard mode it ships when the return arrives intact; in advance mode (if the policy and the customer's history allow it) it ships straight away. If the replacement costs more and the policy says so, the shopper is asked to pay the difference before it ships.
  • carrier_label: a prepaid return label is generated with the merchant's return carrier. If label creation fails the return is still created (has_label: false on the status page).
  • store_dropoff: a drop-off code and QR code are issued for the store.

Not idempotent: each successful call creates a new return.

Rate limit: 10 requests per minute per client, 300 per minute per store.

POST https://api-commerce.nucleoplatform.com/api/oms/v1/public/returns/acme/returns
Authentication: X-Return-Session header
Rate limit: 10 requests per 1m, per IP

Request bodyapplication/json, multipart/form-data

  • payloadCreateReturnrequired
    Child attributes
    • methodstringrequired

      Must be offered in the order view's methods.

      One ofcarrier_labelstore_dropoff
    • store_idstring (uuid)

      Required for store_dropoff; one of methods.stores[].id.

    • languagestring
      One ofitendefres
    • notestring

      Free note for the merchant (trimmed, truncated at 2,000 characters).

    • linesarray of objectrequired
      min items 1
      Attributes of each item
      • idstring (uuid)required

        Order line ID from lines[].id.

      • quantityintegerrequired

        At most the line's returnable.

        min 1
      • reasonstringrequired

        An active reason code.

        Example: too_small
      • resolutionstring
        One ofrefundexchangestore_credit
        default refund
      • exchange_barcodestring

        Required for exchange; one of the line's exchange_options[].barcode, in stock.

      • commentstring

        Free comment on the line (trimmed, truncated at 1,000 characters).

Responses

  • 201Return created.
    • dataobjectrequired
      Child attributes
      • tokenstringrequired

        Return token for /r/{token} and /r/{token}/label. Keep it; it is the only handle.

        pattern ^[A-Za-z0-9]{40}$
      • namestringrequired

        Return number shown to the shopper.

  • 401session_expired: missing, invalid or expired X-Return-Session, or a session of another store.
    • messagestringrequired
  • 404The store does not exist or its returns portal is switched off. The body is an empty message. A slug that does not match ^[a-z0-9][a-z0-9-]{0,63}$ gets the generic route-not-found message.
    • messagestringrequired
  • 422Business rule failure (message is a code, see the description) or invalid photos (standard validation body with errors). invalid_payload when payload is not a JSON object.

    One of the following shapes:

    Message
    • messagestringrequired
    ValidationError
    • messagestringrequired
    • errorsobjectrequired
  • 429Rate limit exceeded. No Retry-After header; wait retry_after seconds.
    • messagestringrequired
      One oftoo_many_requeststoo_many_attempts
    • retry_afterintegerrequired

      Seconds until the limit resets.

Request
curl -X POST https://api-commerce.nucleoplatform.com/api/oms/v1/public/returns/acme/returns \
  -H "X-Return-Session: $NUCLEO_RETURN_SESSION" \
  -H 'Content-Type: application/json' \
  -d '{
  "payload": {
    "method": "carrier_label",
    "language": "it",
    "lines": [
      {
        "id": "9d3f6b1e-2a4c-4e8b-a1f0-6c2d8e4b7a10",
        "quantity": 1,
        "reason": "too_small",
        "resolution": "refund",
        "comment": "Runs a bit tight on the shoulders"
      }
    ]
  }
}'
Response
{
  "data": {
    "token": "Xk2Lm9Qa7Rt4Vb1Nc8Wd3Ye6Zf0Gh5Jp2Ks7Lq4M",
    "name": "#1042-R1"
  }
}

Return status

Public status page and return label, addressed by the return token received at creation (also listed in returns[].token of the order view). Treat the token as a secret link: anyone who has it can see the return and download the label.

get/r/{token}

Get a return's public status

Everything the shopper needs after creating the return: status in plain words, method and instructions (store and drop-off code with QR code, or carrier and tracking number and whether a label is available), fee, refund or store-credit amount and refund state, the exchange order and any price difference, and the returned lines. Works even if the portal has since been switched off.

Reading the status also refreshes the refund state from the sales channel when a refund is pending.

Rate limit: 60 requests per minute per client (shared portal bucket), 1,800 per minute per store.

GET https://api-commerce.nucleoplatform.com/api/oms/v1/public/returns/acme/r/{token}
Authentication: None — public endpoint
Rate limit: 60 requests per 1m, per IP

Path parameters

  • tokenstringrequired

    Return token from POST /returns (data.token) or the order view's returns[].token.

    pattern ^[A-Za-z0-9]{32,64}$
    Example: Xk2Lm9Qa7Rt4Vb1Nc8Wd3Ye6Zf0Gh5Jp2Ks7Lq4M

Responses

  • 200Return status.
    • dataReturnStatusrequired
      Child attributes
      • brandBrandrequired
        Child attributes
        • namestringrequired
          Example: Acme Apparel
        • logo_urlstring (uri) | nullrequired
        • accent_colorstring | nullrequired
          Example: #0F766E
        • support_emailstring (email) | nullrequired
        • support_urlstring (uri) | nullrequired
        • slugstringrequired
          Example: acme
      • languagestringrequired
        One ofitendefres
      • returnobjectrequired
        Child attributes
        • namestringrequired
          Example: #1042-R1
        • order_namestring | nullrequired
          Example: #1042
        • statusstringrequired

          The return in the shopper's words: requested (created, not yet on its way), in_transit, received, checking (received, refund under manual review), completed, refunded, cancelled.

          One ofrequestedin_transitreceivedcheckingcompletedrefundedcancelled
        • created_atstring (date-time) | nullrequired
        • received_atstring (date-time) | nullrequired
        • refunded_atstring (date-time) | nullrequired
        • methodstring | nullrequired
          One ofcarrier_labelstore_dropoffnull
        • storeobject | nullrequired

          Drop-off store, for store_dropoff.

          Child attributes
          • namestring
          • addressstring | null
        • dropoff_codestring | nullrequired

          Code to show at the store desk (also encoded in qr_svg).

          pattern ^R[A-Z0-9]{4}-[A-Z0-9]{5}$
          Example: RK7MP-2XQ9D
        • qr_svgstring | nullrequired

          Inline SVG QR code of dropoff_code.

        • carrierstring | nullrequired

          Return carrier name, when a label was generated.

        • tracking_numberstring | nullrequired
        • has_labelbooleanrequired

          A label can be downloaded from /r/{token}/label.

        • currencystring | nullrequired
          Example: EUR
        • feenumberrequired

          Return fee withheld.

        • refund_amountnumberrequired
        • store_credit_amountnumberrequired
        • refund_statusstring | nullrequired

          waiting (for the items), review (manual check), queued, issued, failed, not_due (nothing to refund, e.g. a straight exchange), none.

          One ofnonewaitingreviewqueuedissuedfailednot_duenull
        • exchangeobject | nullrequired

          The replacement order, for exchanges.

          Child attributes
          • namestring
            Example: #1042-EX1
          • modestring | null

            standard ships when the return arrives intact; advance ships immediately.

            One ofstandardadvancenull
          • shippedboolean
          • differencenumber

            Replacement value minus credit from the return (positive = shopper owes).

          • difference_statusstring | null
            One ofnoneduepaidabsorbedrefundcreditnull
          • linesarray of object
            Attributes of each item
            • titlestring
            • quantityinteger
        • linesarray of objectrequired
          Attributes of each item
          • titlestring | nullrequired
          • sizestring | nullrequired
          • image_urlstring (uri) | nullrequired
          • quantityintegerrequired
          • reasonstring | nullrequired

            Reason label in the return's language.

          • resolutionstringrequired
            One ofrefundexchangestore_credit
          • exchange_titlestring | nullrequired
  • 404Unknown store, malformed or unknown token.
    • messagestringrequired
  • 429Rate limit exceeded. No Retry-After header; wait retry_after seconds.
    • messagestringrequired
      One oftoo_many_requeststoo_many_attempts
    • retry_afterintegerrequired

      Seconds until the limit resets.

Request
curl -X GET https://api-commerce.nucleoplatform.com/api/oms/v1/public/returns/acme/r/Xk2Lm9Qa7Rt4Vb1Nc8Wd3Ye6Zf0Gh5Jp2Ks7Lq4M \
  -H 'Accept: application/json'
Response
{
  "data": {
    "brand": {
      "name": "Acme Apparel",
      "logo_url": "https://cdn.acme.example/logo.svg",
      "accent_color": "#0F766E",
      "support_email": "help@example.com",
      "support_url": "https://shop.acme.example/pages/contact",
      "slug": "acme"
    },
    "language": "it",
    "return": {
      "name": "#1042-R1",
      "order_name": "#1042",
      "status": "requested",
      "created_at": "2026-10-04T09:15:00+00:00",
      "received_at": null,
      "refunded_at": null,
      "method": "carrier_label",
      "store": null,
      "dropoff_code": "RK7MP-2XQ9D",
      "qr_svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 174 174\">…</svg>",
      "carrier": "DHL Express",
      "tracking_number": "1234567890",
      "has_label": true,
      "currency": "EUR",
      "fee": 4.9,
      "refund_amount": 0,
      "store_credit_amount": 0,
      "refund_status": "waiting",
      "exchange": null,
      "lines": [
        {
          "title": "Organic Cotton Tee",
          "size": "M",
          "image_url": "https://cdn.acme.example/products/tee-blk.jpg",
          "quantity": 1,
          "reason": "Troppo piccolo",
          "resolution": "refund",
          "exchange_title": null
        }
      ]
    }
  }
}
get/r/{token}/label

Download the return label

The prepaid return label as a file download: PDF, or ZPL (plain text) for carriers configured to print thermal labels. Only for carrier_label returns whose label was generated (has_label: true). Sent with Cache-Control: private, no-store.

Rate limit: 60 requests per minute per client (shared portal bucket), 1,800 per minute per store.

GET https://api-commerce.nucleoplatform.com/api/oms/v1/public/returns/acme/r/{token}/label
Authentication: None — public endpoint
Rate limit: 60 requests per 1m, per IP

Path parameters

  • tokenstringrequired

    Return token from POST /returns (data.token) or the order view's returns[].token.

    pattern ^[A-Za-z0-9]{32,64}$
    Example: Xk2Lm9Qa7Rt4Vb1Nc8Wd3Ye6Zf0Gh5Jp2Ks7Lq4M

Responses

  • 200The label.
    Headers
    • Content-Disposition Attachment named {return name}-label.pdf or .zpl.
    • Cache-Control

    string (binary)

  • 404Unknown store or token, or no label for this return.
    • messagestringrequired
  • 429Rate limit exceeded. No Retry-After header; wait retry_after seconds.
    • messagestringrequired
      One oftoo_many_requeststoo_many_attempts
    • retry_afterintegerrequired

      Seconds until the limit resets.

Request
curl -X GET https://api-commerce.nucleoplatform.com/api/oms/v1/public/returns/acme/r/Xk2Lm9Qa7Rt4Vb1Nc8Wd3Ye6Zf0Gh5Jp2Ks7Lq4M/label \
  -H 'Accept: application/pdf'
Response
string