> ## 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.

# Pharmacy Orders

> List, view, and update pharmacy order status

# Pharmacy Orders

Manage pharmacy orders — view incoming prescription orders and update their status as you process them.

## List Orders

<ParamField query="page" type="integer" default="0">
  Page number (0-indexed)
</ParamField>

<ParamField query="limit" type="integer" default="50">
  Number of items per page (max 200)
</ParamField>

<ParamField query="status" type="string">
  Filter by status (e.g., `waiting for pharmacy`, `on-hold`, `in-progress`, `completed`)
</ParamField>

<ParamField query="search" type="string">
  Search term. Case-insensitive substring match against shop order name (e.g. `#1234`), pharmacy order name, patient name, order UID, and pharmacy order UID.
</ParamField>

<ParamField query="pharmacy_uid" type="string">
  Required for group-wide API keys
</ParamField>

```bash theme={null}
GET /v1/external_pharmacy_api/pharmacy_orders/
```

### Response

```json theme={null}
{
  "data": [
    {
      "uid": "po-abc123",
      "status": "waiting for pharmacy",
      "name": "#1001",
      "shop_order_name": "#1234",
      "external_status": "OPEN",
      "pharmacy": {
        "uid": "ph-xyz",
        "display_name": "City Pharmacy"
      },
      "order": {
        "uid": "ord-123",
        "delivery_address": {
          "first_name": "Max",
          "last_name": "Mustermann",
          "street": "Hauptstr.",
          "house_number": "1",
          "zip_code": "10115",
          "city": "Berlin",
          "country": "Germany",
          "additional_address": null,
          "province": null
        },
        "invoice_address": {
          "first_name": "Max",
          "last_name": "Mustermann",
          "street": "Hauptstr.",
          "house_number": "1",
          "zip_code": "10115",
          "city": "Berlin",
          "country": "Germany",
          "additional_address": null,
          "province": null
        },
        "priority": 5
      },
      "order_items": [
        {
          "uid": "oi-789",
          "amount": 1,
          "sku": {
            "uid": "sku-456",
            "display_name": "Medication X 100mg",
            "pzn": "12345678"
          },
          "total_paid_amount": 1299
        }
      ],
      "shop_shipping_methods": [
        {
          "uid": "shop-shipping-method-uid",
          "display_name": "DHL Standard",
          "external_id": "shopify-standard",
          "pharmacy_mapping": {
            "pharmacy_uid": "pharmacy-uid",
            "shipping_method_identifier_for_pharmacy": "DHL_STANDARD"
          }
        }
      ],
      "shipping_costs_amount": 499,
      "shipping_costs_currency": "EUR"
    }
  ],
  "totalRegistries": 42,
  "totalPages": 1
}
```

### Order Response Fields

<ResponseField name="shop_order_name" type="string | null">
  Human-readable shop order name from the originating shop (e.g. `#1234`). `null` for orders without a linked shop order.
</ResponseField>

<ResponseField name="shop_shipping_methods" type="array">
  Shop shipping methods attached to the connected shop order. Each entry includes
  the shop method (`uid`, `display_name`, `external_id`) and the pharmacy-specific
  mapping when one has been configured.
</ResponseField>

<ResponseField name="shop_shipping_methods[].pharmacy_mapping" type="object | null">
  Pharmacy-specific mapping for this shop shipping method. When present, it includes
  `pharmacy_uid` and `shipping_method_identifier_for_pharmacy`.
</ResponseField>

<ResponseField name="shipping_costs_amount" type="integer | null">
  Shipping costs in cents, for example `499` for EUR 4.99. This value is separate
  from product line item prices.
</ResponseField>

<ResponseField name="shipping_costs_currency" type="string | null">
  ISO currency code for the shipping costs, for example `EUR`.
</ResponseField>

<ResponseField name="order.priority" type="integer">
  Priority hint for handling order sooner. Higher = more urgent. `0` means no special priority.
</ResponseField>

<Note>
  Shop shipping methods come from connected shop orders. Pharmacists can configure
  pharmacy-specific identifiers for each shop shipping method in the pharmacy tool
  settings. If no mapping exists yet, the API still returns the shop shipping method
  with `pharmacy_mapping: null`. After a pharmacist saves a mapping, future order
  responses include the configured `shipping_method_identifier_for_pharmacy`.
</Note>

## Get Order Details

```bash theme={null}
GET /v1/external_pharmacy_api/pharmacy_orders/{pharmacy_order_uid}
```

Returns the full order including patient data, doctor data, and prescription file (if available).

### Response (additional fields)

```json theme={null}
{
  "uid": "po-abc123",
  "shop_order_name": null,
  "patient_data": {
    "uid": "pat-123",
    "display_name": "Max Mustermann",
    "email": "max@example.com",
    "date_of_birth": "1990-01-15"
  },
  "doctor_data": {
    "uid": "doc-456",
    "display_name": "Dr. Schmidt"
  },
  "prescription_file": {
    "filename": "prescription_001.pdf",
    "content_base64": "JVBERi0xLjQK..."
  },
  "shop_shipping_methods": [
    {
      "uid": "shop-shipping-method-uid",
      "display_name": "DHL Standard",
      "external_id": "shopify-standard",
      "pharmacy_mapping": null
    }
  ],
  "shipping_costs_amount": 499,
  "shipping_costs_currency": "EUR",
  "prepaid": 1,
  "payouts": [
    {
      "status": "projected",
      "amount": 1299,
      "currency": "EUR",
      "component_type": "item_rest",
      "routing_description": "Medication X 100mg rest amount",
      "provider_route_id": null,
      "pharmacy_order_uid": "po-abc123",
      "pharmacy_order_name": "#1001",
      "pharmacy_order_created_at": 1711899000,
      "routing_created_at": null
    }
  ]
}
```

### Payouts

Order detail responses include top-level `payouts`. Each entry uses the same shape as the [Payouts](/api-reference/external-pharmacy/payouts) endpoint.

<ResponseField name="payouts" type="array">
  Payout components for this pharmacy order where the requested pharmacy is the receiver. Paid physical-prescription orders return `projected` payout previews based on current order values and routing configuration. Completed orders return `routed` payouts once a persisted split-payment route exists.
</ResponseField>

<ResponseField name="payouts[].status" type="string">
  `projected` for an indicative preview, or `routed` for a persisted split-payment route created after pharmacy order completion.
</ResponseField>

<ResponseField name="payouts[].amount" type="integer">
  Payout amount in cents.
</ResponseField>

<ResponseField name="payouts[].currency" type="string">
  ISO 4217 currency code, for example `EUR`.
</ResponseField>

<ResponseField name="payouts[].component_type" type="string">
  The payout component, such as `item_rest`, `item_markup`, or `shipping`.
</ResponseField>

<ResponseField name="payouts[].routing_description" type="string | null">
  Human-readable description of the routed or projected component.
</ResponseField>

<ResponseField name="payouts[].provider_route_id" type="string | null">
  Payment provider route identifier. This is populated for routed payouts when the provider returned an identifier, and `null` for projected payouts.
</ResponseField>

<ResponseField name="payouts[].pharmacy_order_uid" type="string">
  UID of the related pharmacy order.
</ResponseField>

<ResponseField name="payouts[].pharmacy_order_name" type="string | null">
  Human-readable pharmacy order name, for example `#1001`.
</ResponseField>

<ResponseField name="payouts[].pharmacy_order_created_at" type="integer">
  Unix timestamp when the pharmacy order was created.
</ResponseField>

<ResponseField name="payouts[].routing_created_at" type="integer | null">
  Unix timestamp when the split-payment route was created. This is `null` for `projected` payouts and populated for `routed` payouts.
</ResponseField>

<Warning>
  Actual routing only happens when the pharmacy order is completed. `projected` payouts are indicative, only shown for paid physical-prescription orders, and can change before completion. `routed` payout values are only populated after completion and routing exists.
</Warning>

## Update Order Status

```bash theme={null}
PATCH /v1/external_pharmacy_api/pharmacy_orders/{pharmacy_order_uid}/status
```

### Request Body

```json theme={null}
{
  "status": "in-progress"
}
```

<ParamField body="status" type="string" required>
  New order status. See the table below for accepted values.
</ParamField>

<ParamField body="comment" type="string">
  Free-text explanation for the status change. **Required (and must be non-blank) when transitioning to `on-hold` from any other status** — the comment becomes the description of the admin issue thread that is automatically opened for the on-hold. Ignored for all other status transitions.
</ParamField>

### Allowed Status Values

| Status                 | Description                                                        |
| ---------------------- | ------------------------------------------------------------------ |
| `waiting for pharmacy` | Order is in your queue, waiting to be processed                    |
| `pending review`       | Order is being reviewed                                            |
| `on-hold`              | Order is paused while the pharmacy and admin team clarify an issue |
| `in-progress`          | Order is being prepared                                            |
| `ready_for_pickup`     | Order is packed and ready for pickup or shipping                   |
| `cancelled`            | Order was cancelled                                                |

<Warning>
  Do not set `completed` through this endpoint. Use the dedicated complete order endpoint below so RxScale can finalize the order, reduce stock, and publish the related events.
</Warning>

### Putting an Order On Hold

When you move an order into `on-hold`, you must include a `comment` describing why the order is being paused. RxScale opens an admin issue thread automatically and uses your comment as the thread description so the admin team has the context they need to follow up.

```bash theme={null}
curl -X PATCH "https://api.rxscale.com/v1/external_pharmacy_api/pharmacy_orders/po-abc123/status" \
  -H "X-API-Key: your-api-key-here" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "on-hold",
    "comment": "Out of stock until 2026-06-01"
  }'
```

A request without a `comment`, or with a comment that is only whitespace, returns a `400` response with body:

```json theme={null}
{
  "error": {
    "comment": ["A comment is required when setting an order on hold"]
  }
}
```

Subsequent `on-hold` PATCH requests for an order that is already `on-hold` do not require a new comment — they are treated as idempotent re-sends.

## Complete Order

```bash theme={null}
PATCH /v1/external_pharmacy_api/pharmacy_orders/{pharmacy_order_uid}/complete_order
```

Completes the pharmacy order, reduces stock for the pharmacy SKUs on the order, and publishes order update notifications. Requires the `orders_write` permission.

<ParamField query="pharmacy_uid" type="string">
  Required for group-wide API keys
</ParamField>

### Request Body

```json theme={null}
{
  "tracking_links": [
    {
      "tracking_link": "https://tracking.example.com/parcel/123",
      "carrier": "DHL"
    }
  ]
}
```

`tracking_links` is optional. If provided, the first tracking link is forwarded with the shipment update.
Allowed `carrier` values are `DHL`, `DPD`, `UPS`, `Hermes`, `FedEx`, and `Other`.

```bash theme={null}
curl -X PATCH "https://api.rxscale.com/v1/external_pharmacy_api/pharmacy_orders/po-abc123/complete_order" \
  -H "X-API-Key: your-api-key-here" \
  -H "Content-Type: application/json" \
  -d '{
    "tracking_links": [
      {
        "tracking_link": "https://tracking.example.com/parcel/123",
        "carrier": "DHL"
      }
    ]
  }'
```

### Response

```json theme={null}
{
  "uid": "po-abc123",
  "status": "completed",
  "name": "#1001",
  "external_status": "OPEN",
  "pharmacy": {
    "uid": "pharmacy-uid",
    "display_name": "Example Pharmacy"
  },
  "order_items": [
    {
      "uid": "oi-789",
      "amount": 1,
      "sku": {
        "uid": "sku-456",
        "display_name": "Medication X 100mg",
        "pzn": "12345678"
      }
    }
  ],
  "shop_shipping_methods": [
    {
      "uid": "shop-shipping-method-uid",
      "display_name": "DHL Standard",
      "external_id": "shopify-standard",
      "pharmacy_mapping": {
        "pharmacy_uid": "pharmacy-uid",
        "shipping_method_identifier_for_pharmacy": "DHL_STANDARD"
      }
    }
  ],
  "shipping_costs_amount": 499,
  "shipping_costs_currency": "EUR"
}
```

### Validation Error Response

When `tracking_links` contains an unsupported carrier or an invalid tracking link, the API returns `400` with the validation error and the pharmacy summary so you can map the error back to the affected pharmacy. If the order is already completed, calling `complete_order` again remains idempotent only when no tracking data is sent; tracking links on an already-completed order are rejected with `400` so shipment details are not silently dropped.

```json theme={null}
{
  "error": {
    "tracking_links": {
      "0": {
        "tracking_link": ["Invalid tracking link"]
      }
    }
  },
  "pharmacy": {
    "uid": "pharmacy-uid",
    "display_name": "Example Pharmacy"
  }
}
```
