# Create a return

`POST /v2/orders/return`

**Base URLs:**

- Sandbox: `https://api.sandbox.bobgo.co.za`
- Production: `https://api.bobgo.co.za`

**Authentication:** Bearer token required (see the Authentication page).

## Example request

```bash
curl -X POST 'https://api.sandbox.bobgo.co.za/v2/orders/return' \
  -H "content-type: application/json" \
  -H "Authorization: Bearer <API_KEY>" \
  -d '{
  "order_id": 5531,
  "provider_slug": "demo",
  "service_level_code": "ECO",
  "collection_address": {
    "type": "residential",
    "street_address": "21 Harley Street",
    "local_area": "Ferndale",
    "city": "Randburg",
    "zone": "Gauteng",
    "country": "ZA",
    "code": "2194"
  },
  "delivery_address": {
    "type": "business",
    "company": "Bob Go",
    "street_address": "126 Dallas Avenue",
    "local_area": "Waterkloof Glen",
    "city": "Pretoria",
    "zone": "Gauteng",
    "country": "ZA",
    "code": "0010"
  },
  "parcels": [
    {
      "description": "Standard sleeve",
      "submitted_length_cm": 42,
      "submitted_width_cm": 38,
      "submitted_height_cm": 5,
      "submitted_weight_kg": 1
    }
  ],
  "declared_value": 350,
  "collection_contact_name": "John",
  "collection_contact_surname": "Doe",
  "collection_contact_email": "john@doe.com",
  "collection_contact_mobile_number": "0123456789",
  "delivery_contact_name": "Jane",
  "delivery_contact_surname": "Doe",
  "delivery_contact_email": "jane@doe.com",
  "delivery_contact_mobile_number": "0123456789",
  "instructions_collection": "Ring the bell at the gate"
}'
```

Books a return shipment against an existing order: the courier collects from
the buyer and delivers back to you. It is a shipment like any other, needing
a rate, a courier and a service level, but it hangs off the order so the
platform can tie the return to what was originally sold.

Get rates for the return the same way you would for an outbound shipment, with
[`POST /v2/rates`](../8_Rates/rates.md): the collection address is the buyer's
and the delivery address is yours.

## Request

Nothing is copied from the order: send both addresses, even though the
collection address is usually the order's delivery address.

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `order_id` | integer | yes | The order being returned against. |
| `provider_slug` | string | yes | The courier, from the rate you selected. |
| `service_level_code` | string | yes | The service level, from the rate you selected. |
| `collection_address` | object | yes | Where the courier collects, usually the buyer. Not needed when you send `collection_pickup_point_location_id`. |
| `delivery_address` | object | yes | Where the goods come back to. Not needed when you send `pickup_point_location_id`. |
| `parcels` | array | yes | What is coming back. See [parcel fields](../4_Important%20concepts/README.md#parcels). |
| `items` | array | no | The order lines being returned, as `{ "order_item_id": …, "qty": … }`. Each must be a line on this order, or the request is refused with `400`. Leave it out to return every line in full. |
| `declared_value` | number | no | Value of the contents in ZAR. |
| `selected_rate_request_id` | integer | no | The `id` from the rates response, for the funds check. |
| `collection_min_date` | timestamp | no | Earliest date the courier may collect. |
| `collection_after` / `collection_before` | string | no | Collection window, `hh:mm:ss`. |
| `instructions_collection` | string | no | Note for the collection driver. |
| `instructions_delivery` | string | no | Note for the delivery driver. |
| `collection_contact_name` | string | no | Who the courier collects from. First name. |
| `collection_contact_surname` | string | no | |
| `collection_contact_mobile_number` | string | no | |
| `collection_contact_email` | string | no | Checked when you send it. |
| `delivery_contact_name` | string | no | Who receives it. First name. |
| `delivery_contact_surname` | string | no | |
| `delivery_contact_mobile_number` | string | no | |
| `delivery_contact_email` | string | no | Checked when you send it. |
| `custom_tracking_reference` | string | no | Your own reference. |
| `shipping_label_emails` | array of string | no | Email the label to these addresses. |
| `pickup_point_location_id` | integer | no | Return to a pickup point. |
| `collection_pickup_point_location_id` | integer | no | Collect from a pickup point. |

## Response

```json
{
  "order_fulfillment": { "...": "..." },
  "shipment": { "...": "..." }
}
```

The return is created as a fulfilment on the order, with the return shipment
alongside it. `shipment.tracking_reference` is what you track, and
`shipment.submission_status` tells you whether it reached the courier. It is
asynchronous here exactly as it is on
[`POST /v2/shipments`](../9_Shipments/shipment_create.md#statuses).

A return whose shipment could not be created still comes back `200`. Check
`order_fulfillment.status`: on `failed`, `order_fulfillment.failed_reason` says
why. It usually comes back `pending` and can still fail afterwards, for example
with `no-rates` on a service level that was not quoted for the lane, so read it
again with [`GET /v2/order-fulfillments`](order_fulfillments.md).

A return does not send the `fulfillment/created` webhook. Its shipment sends
`shipment_submission_status/updated` and `tracking/updated` like any other
shipment. See [Webhooks](../11_Webhooks/README.md).
