# Forward and track dropship orders

import StepVideo from '@/components/StepVideo'

# Forward and track dropship orders

<StepVideo id="aff-12-dropship-orders" />

Forward an order only after your storefront has accepted the customer's payment. You need an approved active account, the private live dropship token, enough available credit and a product that can ship to the destination.

## Map the paid order

1. Recheck `GET /products` for price, availability and allowed shipping regions. The current real SKU `KK-HW-001` is US-only.
2. Map your store's product variant to that catalog SKU. Do not send the sandbox test SKU for a real shipment.
3. Use the paid storefront order's stable reference as `externalOrderId` and include the customer contact details, shipping address, quantities and shipping method.
4. Submit from your backend to `POST /api/dropship/v1/orders` using the **live token**. Store the exact request and response with appropriate protection for customer data.
5. Save the returned KeepKey order ID and [settlement details](/docs/dropshipping/settlements) alongside the external order ID.

The payload fields are described in the [sandbox guide](/docs/dropshipping/api#prepare-a-sandbox-order). A real request changes the SKU, customer details and external ID to the actual paid order and uses the live credential. Switching credentials is a real mode change; an HTTP success alone does not establish shipment.

For a Shopify storefront, use the portal's [Shopify walkthrough](https://affiliates.keepkey.com/dropship/docs#shopify) to arrange forwarding from your backend. Keep the fulfillment token out of themes and public JavaScript.

## Look up an order

Use either `keepKeyOrderId` or `externalOrderId` on `GET /orders`. For example, with your live token already set privately:

```bash
curl --fail-with-body --get \
  'https://affiliates.keepkey.com/api/dropship/v1/orders' \
  -H "Authorization: Bearer ${KEEPKEY_DROPSHIP_LIVE_TOKEN}" \
  --data-urlencode 'externalOrderId=YOUR_STOREFRONT_ORDER_ID'
```

Compare the IDs, `sandbox` flag, order status, `fulfillment`, tracking fields and settlement state with your storefront record. A lookup with the wrong credential or mode is not evidence about the intended live order.

## Interpret the state

| Field or result | Meaning and action |
| --- | --- |
| `status: received` | The request exists. It is not shipping confirmation. |
| `fulfillment: pending` | The fulfillment push has not completed; inspect state before resubmitting. Temporary push failures can be retried by the service. |
| `fulfillment: submitted` | The order was submitted for fulfillment. This is still distinct from shipment. |
| `fulfillment: rejected` | A permanent fulfillment rejection was recorded; inspect the error and reconcile before trying again. |
| Null tracking fields or `estimatedShippingDate` | No value was supplied. Do not turn it into a delivery estimate. |
| Tracking details or a shipment update | Reconcile the identified order and update your customer-facing record from the confirmed result. |

## Handle errors without duplicating orders

| HTTP / error | Next step |
| --- | --- |
| 401 `auth_failure` | Check the token, mode and whether it was rotated |
| 402 `insufficient_credit` | Reconcile settlements and available capacity |
| 403 `account_suspended` | Resolve the blocking account state |
| 409 `duplicate_external_order_id` | Compare the original payload; do not silently change it |
| 422 `unsupported_shipping_region` | Correct the destination or decline the unsupported order before fulfillment |
| 422 `fulfillment_rejected` | Inspect the permanent failure; the handler unwinds that rejected order's credit |

For a timeout or temporary transport error, look up the original ID and use a bounded retry with the same ID and identical body. Read permanent failures before changing anything. Use [signed webhooks with a lookup fallback](/docs/dropshipping/webhooks) to keep the store synchronized.
