> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rxscale.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Order Intake

> Create and manage orders from your own sales channel via the Management API

# Order Intake

If your organisation does not sell through Shopify, order intake lets you push orders into RxScale
directly from your own sales channel -- your own website, POS system, or any other system of
record. Everything downstream (prescriptions, pharmacy routing, fulfillment) works exactly the same
way it does for a Shopify order; only how the order gets into RxScale differs.

<Note>
  This is for **your own** integration, pushing orders into **your own** organisation. If you are a
  telemedicine provider integrating into one of RxScale's customer shops, see the
  [Public API](/api-reference/public/orders) instead.
</Note>

## Before You Start

* **Required permission:** every endpoint on this page requires `order:write` on your API key.
* **A shop must exist first.** Orders are created against a `shop_identifier` that RxScale configures
  for your organisation when the integration is set up. Contact your RxScale account manager if you
  don't have one yet.
* **Order status for your own customers lives elsewhere.** This page only covers pushing orders in.
  To check the status of an order as it moves through prescription review and pharmacy fulfillment,
  use [`GET /v1/management/orders`](/api-reference/management/orders) -- the read endpoints already
  documented on the Orders page.

## Four Operations

| Method  | Endpoint                                                                    | Effect                                                                             |
| ------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| `POST`  | `/orders`                                                                   | Create an order, including at least one fulfillment and its items                  |
| `POST`  | `/orders/{order_external_id}/fulfillments`                                  | Add a **new** fulfillment to an existing order                                     |
| `PATCH` | `/orders/{order_external_id}`                                               | Update item-free order fields (addresses, priority, customer email, shipping cost) |
| `POST`  | `/orders/{order_external_id}/fulfillments/{fulfillment_external_id}/cancel` | Cancel a fulfillment, while it is still cancellable                                |

**Fulfillments are immutable.** There is no endpoint to change the items on a fulfillment once it
is created. To change what is dispensed, cancel the fulfillment and create a new one with the
corrected items -- this also starts a fresh prescription for the new items.

## Create an Order

```bash theme={null}
POST /v1/management/orders
```

**Required permission:** `order:write`

Creates an order together with its first fulfillment (or several fulfillments at once). Creation is
**strictly once per `external_id`** -- see [Retries and Duplicate Requests](#retries-and-duplicate-requests)
below.

### Request Body

| Field               | Type             | Required | Description                                                                                                               |
| ------------------- | ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------- |
| `shop_identifier`   | string           | Yes      | The identifier of your shop, as configured by RxScale                                                                     |
| `external_id`       | string           | Yes      | Your own unique id for this order. Creating an order with the same `external_id` twice is rejected -- see below           |
| `name`              | string           | No       | A human-readable order name/number, shown in the RxScale back office. Defaults to `external_id`                           |
| `customer`          | object           | Yes      | See [Customer object](#customer-object)                                                                                   |
| `delivery_address`  | object           | Yes      | See [Address object](#address-object)                                                                                     |
| `invoice_address`   | object           | No       | See [Address object](#address-object). Defaults to `delivery_address` when omitted                                        |
| `shipping_cost`     | object           | No       | See [Money object](#money-object)                                                                                         |
| `shipping_methods`  | array of strings | No       | Free-text shipping method labels (e.g. `["standard"]`)                                                                    |
| `priority`          | integer          | No       | A priority hint used for internal queueing                                                                                |
| `on_hold`           | boolean          | No       | When `true`, the order is created on hold and does not proceed to a doctor or pharmacy automatically. Defaults to `false` |
| `hold_comment`      | string           | No       | A note explaining why the order is on hold. Only meaningful together with `on_hold: true`                                 |
| `doctor_uid`        | string           | No       | Pre-assign a specific RxScale doctor to review the order's prescriptions                                                  |
| `pharmacy_uid`      | string           | No       | Pre-assign a specific pharmacy for the whole order                                                                        |
| `pharmacy_email`    | string           | No       | An email address to notify alongside `pharmacy_uid`                                                                       |
| `referral_scan_uid` | string           | No       | Attribution reference for a referral link scan that led to this order                                                     |
| `fulfillments`      | array of objects | Yes      | At least one. See [Fulfillment object](#fulfillment-object)                                                               |

#### Customer Object

| Field   | Type   | Required | Description                                                                                  |
| ------- | ------ | -------- | -------------------------------------------------------------------------------------------- |
| `id`    | string | Yes      | Your own stable id for this customer. Reused across orders to recognise a returning customer |
| `email` | string | No       | The customer's email address                                                                 |

#### Address Object

| Field                | Type   | Required | Description                           |
| -------------------- | ------ | -------- | ------------------------------------- |
| `first_name`         | string | Yes      |                                       |
| `last_name`          | string | Yes      |                                       |
| `street`             | string | Yes      |                                       |
| `house_number`       | string | Yes      |                                       |
| `zip_code`           | string | Yes      |                                       |
| `city`               | string | Yes      |                                       |
| `country`            | string | Yes      | 2-letter ISO country code (e.g. `DE`) |
| `additional_address` | string | No       | Apartment number, care-of line, etc.  |
| `province`           | string | No       | State/region, where applicable        |

#### Money Object

RxScale never accepts decimal or floating-point amounts -- amounts are always **integers in the
currency's minor unit** (cents for EUR), the same convention used throughout the platform.

| Field      | Type    | Required | Description                                   |
| ---------- | ------- | -------- | --------------------------------------------- |
| `amount`   | integer | Yes      | Amount in minor units, e.g. `1998` for €19.98 |
| `currency` | string  | Yes      | 3-letter ISO currency code (e.g. `EUR`)       |

#### Fulfillment Object

A fulfillment is a group of items that ships and is prescribed together. Most orders have one; an
order with items from different pharmacies or with different readiness (e.g. one item ready to ship,
one still pending a prescription) has several.

| Field                      | Type             | Required | Description                                                                                                                               |
| -------------------------- | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `external_id`              | string           | Yes      | Your own unique id for this fulfillment                                                                                                   |
| `items`                    | array of objects | Yes      | At least one. See [Item object](#item-object)                                                                                             |
| `destination_pharmacy_uid` | string           | No       | Route this fulfillment to a specific pharmacy, bypassing automatic pharmacy selection                                                     |
| `location_id`              | string           | No       | An alternate way to steer pharmacy routing, when your integration maps to RxScale-configured locations rather than pharmacy UIDs directly |
| `prescriptions`            | array of objects | No       | Signed PDFs to upload inline. See [Linking a Prescription](#linking-a-prescription)                                                       |

#### Item Object

| Field                    | Type    | Required | Description                                                                                                                                                                                                                       |
| ------------------------ | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `external_id`            | string  | Yes      | Your own unique id for this line, unique across the whole order (not just this fulfillment)                                                                                                                                       |
| `sku_reference`          | string  | Yes      | The SKU's variant identifier in your catalogue, as configured in RxScale                                                                                                                                                          |
| `product_reference`      | string  | No       | The product identifier in your catalogue. Required whenever `sku_reference` alone does not uniquely resolve a product in your shop's configuration -- ask your RxScale contact if you're unsure whether your catalogue needs this |
| `quantity`               | integer | Yes      | Must be at least `1`                                                                                                                                                                                                              |
| `total_paid`             | object  | Yes      | See [Money object](#money-object). This is the amount the customer paid for this line -- RxScale holds product identity, you hold price truth                                                                                     |
| `prescription_uid`       | string  | No       | Link to an existing signed prescription. See [Linking a Prescription](#linking-a-prescription)                                                                                                                                    |
| `prescription_reference` | string  | No       | Link to a PDF uploaded inline on this fulfillment. See [Linking a Prescription](#linking-a-prescription)                                                                                                                          |
| `anamnesis_uid`          | string  | No       | Link to a completed questionnaire response, for an RxScale doctor to review. See [Linking a Prescription](#linking-a-prescription)                                                                                                |
| `fulfillment_method`     | string  | No       | A hint used to select the delivery type (e.g. shipping vs. pickup) when your shop has more than one configured                                                                                                                    |

### Linking a Prescription

A line item needs a prescription whenever its product requires one. There are four ways to satisfy
that, and every line uses exactly one of them:

<AccordionGroup>
  <Accordion title="Over the counter -- no prescription needed">
    Leave `prescription_uid`, `prescription_reference`, and `anamnesis_uid` all unset. Only valid for
    products in your catalogue that are configured as not requiring a prescription.
  </Accordion>

  <Accordion title="Send to an RxScale doctor">
    Set `anamnesis_uid` to the uid of a completed questionnaire response for this customer. An
    RxScale doctor reviews it and issues the prescription; the order moves to
    `waiting for doctor` until they do.
  </Accordion>

  <Accordion title="Reference a prescription you already have">
    Set `prescription_uid` to the uid of a prescription that is already **signed** -- for example,
    one your integration obtained earlier through another RxScale flow. The prescription must
    already belong to your organisation.
  </Accordion>

  <Accordion title="Upload a signed PDF inline">
    Add an entry to the fulfillment's own `prescriptions` array: `{"id": "your-reference",
            "pdf_base64": "..."}`. The PDF is validated for a qualified electronic signature (QES) as part
    of the request -- an unsigned or invalid PDF rejects the whole order, nothing is created. On the
    line item, set `prescription_reference` to the same `id` you used in `prescriptions`. RxScale
    turns the upload into a prescription and links it to the line automatically; from that point on
    it behaves exactly like the previous option.

    ```json theme={null}
    {
      "external_id": "ff-1",
      "items": [
        {
          "external_id": "line-1",
          "sku_reference": "variant-123",
          "product_reference": "prod-123",
          "quantity": 1,
          "total_paid": { "amount": 4500, "currency": "EUR" },
          "prescription_reference": "rx-upload-1"
        }
      ],
      "prescriptions": [
        { "id": "rx-upload-1", "pdf_base64": "JVBERi0xLjQK..." }
      ]
    }
    ```
  </Accordion>
</AccordionGroup>

<Warning>
  A line cannot set both `prescription_uid` and `prescription_reference` -- pick one. A
  `prescription_reference` that names no entry in this fulfillment's own `prescriptions` array is
  rejected before anything is created.
</Warning>

### Example Request

```bash theme={null}
curl -X POST "https://api.rxscale.com/v1/management/orders" \
  -H "X-API-Key: your-api-key-here" \
  -H "Content-Type: application/json" \
  -d '{
    "shop_identifier": "my-shop",
    "external_id": "order-10231",
    "customer": {
      "id": "cust-4471",
      "email": "patient@example.com"
    },
    "delivery_address": {
      "first_name": "Ada",
      "last_name": "Lovelace",
      "street": "Hauptstraße",
      "house_number": "1",
      "zip_code": "10115",
      "city": "Berlin",
      "country": "DE"
    },
    "fulfillments": [
      {
        "external_id": "ff-1",
        "items": [
          {
            "external_id": "line-1",
            "sku_reference": "variant-123",
            "product_reference": "prod-123",
            "quantity": 2,
            "total_paid": { "amount": 1998, "currency": "EUR" }
          }
        ]
      }
    ]
  }'
```

### Response (201 Created)

```json theme={null}
{
  "order_uid": "ord-abc123",
  "external_id": "order-10231"
}
```

| Field         | Type   | Description                                                                                                                                                                |
| ------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `order_uid`   | string | The RxScale-assigned order UID. Use it with [`GET /v1/management/orders/{order_uid}`](/api-reference/management/orders#get-order-details) to check on the order afterwards |
| `external_id` | string | Echoes the `external_id` you sent                                                                                                                                          |

### Error Responses

| Status | Code                   | Description                                                                                                                                                                                                       |
| ------ | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | `sku_not_found`        | One or more items reference a `sku_reference`/`product_reference` combination not in your catalogue. The response also includes `missing_item_ids`, the `external_id` of each offending line. No order is created |
| `400`  | *(none)*               | The request body failed validation (missing/invalid field, an invalid inline PDF, a `prescription_reference` that names no upload, etc.). The response's `error` field describes what failed                      |
| `401`  | *(none)*               | Missing or invalid API key                                                                                                                                                                                        |
| `403`  | *(none)*               | Missing `order:write` permission                                                                                                                                                                                  |
| `404`  | *(none)*               | No shop found for `shop_identifier` in your organisation                                                                                                                                                          |
| `409`  | `order_already_exists` | An order with this `external_id` already exists. The response body carries the existing order's `order_uid` -- see [Retries and Duplicate Requests](#retries-and-duplicate-requests)                              |

<Note>
  When a request is rejected, **nothing is created** -- not the order, not a prescription from an
  inline PDF, nothing. `external_id` stays free to retry with a corrected payload.
</Note>

### Retries and Duplicate Requests

Order creation is strictly once per `external_id`: POSTing the same `external_id` a second time
always returns `409` with `code: "order_already_exists"`, even if the first request's response
never reached you (a timeout, a dropped connection). The `409` body carries the existing order's
`order_uid`, so recovering from a lost response needs no follow-up call -- just retry with the same
payload and read `order_uid` off the error:

```json theme={null}
{
  "code": "order_already_exists",
  "error": "Order order-10231 already exists for shop my-shop",
  "order_uid": "ord-abc123"
}
```

Alternatively, the same information is available via a lookup:

```bash theme={null}
curl -X GET "https://api.rxscale.com/v1/management/orders?shop_identifier=my-shop&shop_order_external_id=order-10231" \
  -H "X-API-Key: your-api-key-here"
```

This is the same [List Orders](/api-reference/management/orders#look-up-a-specific-shop-order)
endpoint already documented on the Orders page, filtered down to at most one result.

## Add a Fulfillment

```bash theme={null}
POST /v1/management/orders/{order_external_id}/fulfillments
```

<ParamField path="order_external_id" type="string" required>
  Your `external_id` for the existing order
</ParamField>

**Required permission:** `order:write`

Adds a **new** fulfillment (and its items) to an order that already exists. The request body is a
single [Fulfillment object](#fulfillment-object) -- not wrapped in an order. Use this when items in
the same order become available at different times, or need to be split across pharmacies.

A fulfillment `external_id` that already exists on this order is rejected: fulfillments cannot be
changed once created, only cancelled and replaced.

### Example Request

```bash theme={null}
curl -X POST "https://api.rxscale.com/v1/management/orders/order-10231/fulfillments" \
  -H "X-API-Key: your-api-key-here" \
  -H "Content-Type: application/json" \
  -d '{
    "external_id": "ff-2",
    "items": [
      {
        "external_id": "line-2",
        "sku_reference": "variant-456",
        "product_reference": "prod-456",
        "quantity": 1,
        "total_paid": { "amount": 2500, "currency": "EUR" }
      }
    ]
  }'
```

### Response (201 Created)

```json theme={null}
{
  "order_uid": "ord-abc123",
  "external_id": "ff-2"
}
```

### Error Responses

| Status | Code                    | Description                                                                                                                                                                                                                       |
| ------ | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | `sku_not_found`         | One or more items reference an unknown SKU. `missing_item_ids` lists the offending `external_id`s                                                                                                                                 |
| `400`  | *(none)*                | The request body failed validation                                                                                                                                                                                                |
| `401`  | *(none)*                | Missing or invalid API key                                                                                                                                                                                                        |
| `403`  | *(none)*                | Missing `order:write` permission                                                                                                                                                                                                  |
| `404`  | *(none)*                | No order found for `external_id` in your organisation                                                                                                                                                                             |
| `409`  | `fulfillment_immutable` | A fulfillment with this `external_id` already exists on the order                                                                                                                                                                 |
| `409`  | `order_not_updatable`   | The order is in a status that no longer accepts new fulfillments (for example, `waiting for pharmacy`). A **completed** order is the exception: adding a fulfillment to it reopens it automatically instead of returning an error |

## Update an Order

```bash theme={null}
PATCH /v1/management/orders/{order_external_id}
```

<ParamField path="order_external_id" type="string" required>
  Your `external_id` for the existing order
</ParamField>

**Required permission:** `order:write`

Updates order-level fields that are not tied to items. **Items are never accepted here** -- they
always arrive inside a fulfillment (see [Add a Fulfillment](#add-a-fulfillment)); a request body
containing an `items` key is rejected.

### Request Body

All fields are optional; send only what you want to change.

| Field              | Type    | Description                           |
| ------------------ | ------- | ------------------------------------- |
| `delivery_address` | object  | See [Address object](#address-object) |
| `invoice_address`  | object  | See [Address object](#address-object) |
| `priority`         | integer |                                       |
| `customer_email`   | string  |                                       |
| `shipping_cost`    | object  | See [Money object](#money-object)     |

### Example Request

```bash theme={null}
curl -X PATCH "https://api.rxscale.com/v1/management/orders/order-10231" \
  -H "X-API-Key: your-api-key-here" \
  -H "Content-Type: application/json" \
  -d '{
    "delivery_address": {
      "first_name": "Ada",
      "last_name": "Lovelace",
      "street": "Hauptstraße",
      "house_number": "2",
      "zip_code": "10115",
      "city": "Berlin",
      "country": "DE"
    }
  }'
```

### Response (200 OK)

```json theme={null}
{
  "status": "updated"
}
```

### Error Responses

| Status | Code                  | Description                                                                                                                                                             |
| ------ | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | *(none)*              | The request body failed validation, or contained an `items` key                                                                                                         |
| `401`  | *(none)*              | Missing or invalid API key                                                                                                                                              |
| `403`  | *(none)*              | Missing `order:write` permission                                                                                                                                        |
| `404`  | *(none)*              | No order found for `external_id` in your organisation                                                                                                                   |
| `409`  | `order_not_updatable` | The order is in a status that no longer accepts updates (for example, already completed)                                                                                |
| `409`  | `address_locked`      | You're changing `delivery_address` or `invoice_address` on an order that already has an active pharmacy order. Addresses lock once a pharmacy is preparing the shipment |

## Cancel a Fulfillment

```bash theme={null}
POST /v1/management/orders/{order_external_id}/fulfillments/{fulfillment_external_id}/cancel
```

<ParamField path="order_external_id" type="string" required>
  Your `external_id` for the order
</ParamField>

<ParamField path="fulfillment_external_id" type="string" required>
  Your `external_id` for the fulfillment to cancel
</ParamField>

**Required permission:** `order:write`

Cancels a fulfillment. This is the only way to change what a fulfillment contains -- cancel it, then
[add a new fulfillment](#add-a-fulfillment) with the corrected items.

<Warning>
  Cancellation is only possible while the fulfillment's prescription (if it has one) has not yet
  reached a final state, and while no pharmacy is actively processing it. Once a doctor signs or
  declines the prescription, or a pharmacy starts working the order, cancelling is refused.
</Warning>

### Example Request

```bash theme={null}
curl -X POST "https://api.rxscale.com/v1/management/orders/order-10231/fulfillments/ff-2/cancel" \
  -H "X-API-Key: your-api-key-here"
```

### Response (200 OK)

```json theme={null}
{
  "status": "cancelled"
}
```

### Error Responses

| Status | Code                                   | Description                                                                                 |
| ------ | -------------------------------------- | ------------------------------------------------------------------------------------------- |
| `401`  | *(none)*                               | Missing or invalid API key                                                                  |
| `403`  | *(none)*                               | Missing `order:write` permission                                                            |
| `404`  | *(none)*                               | No order or fulfillment found for the given `external_id`s in your organisation             |
| `409`  | `prescription_already_finished`        | The fulfillment's prescription is already signed or declined and can no longer be cancelled |
| `409`  | `fulfillment_locked_by_pharmacy_order` | A pharmacy is already actively processing this fulfillment                                  |

## Where Order Status Lives

This page covers pushing orders **into** RxScale. To track an order after that -- its status, which
prescription is attached, which pharmacy order was created -- use
[`GET /v1/management/orders`](/api-reference/management/orders) and
[`GET /v1/management/orders/{order_uid}`](/api-reference/management/orders#get-order-details),
already documented on the Orders page. If you are instead a telemedicine provider tracking orders
you placed through the Public API, order status for that flow lives in the
[Public API](/api-reference/public/orders) -- not here.
