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

# Create Shipment

> Create a logistics shipment order with specified origin and destination

Create a shipment order from the specified origin location. The destination is automatically determined based on the location's configuration.

## Request

### Body parameters

<ParamField body="location_id" type="string" required>
  Origin test location UUID. The location must be active and within your API key's access context.
  Use [List Locations](/api/locations/list-locations) to find available location IDs.
</ParamField>

<ParamField body="appointment_id" type="string">
  Optional appointment UUID to link this shipment to at creation time. The appointment must be
  within your API key's access context. The link surfaces inline as an entry in the shipment's
  `appointments` array, and conversely as an entry in the appointment's `shipments` array. To link
  additional appointments after creation, or remove the initial link, use [Attach Appointments to
  Shipment](/api/shipments/attach-appointments-to-shipment) and [Detach Appointments from
  Shipment](/api/shipments/detach-appointments-from-shipment).
</ParamField>

<ParamField body="pickup_date" type="string" required>
  Pickup date in `YYYY-MM-DD` format (e.g., `2026-04-15`), interpreted in the origin location's
  timezone. Must be a weekday (Monday–Friday), today or in the future. Same-day pickups are not
  available after 16:00 Europe/Berlin.
</ParamField>

<ParamField body="pickup_time_from" type="string" required>
  Earliest pickup time in `HH:MM` format (e.g., `09:00`), interpreted as wall-clock time in the
  origin location's timezone. Must be between `09:00` and `19:00`.
</ParamField>

<ParamField body="pickup_time_till" type="string" required>
  Latest pickup time in `HH:MM` format (e.g., `12:00`), interpreted as wall-clock time in the origin
  location's timezone. Must be between `09:00` and `19:00`. The window (`pickup_time_till -
      pickup_time_from`) must be at least 2 hours.
</ParamField>

<ParamField body="package_count" type="integer" default="1">
  Number of packages. Defaults to `1`.
</ParamField>

<ParamField body="weight" type="number" default="1">
  Weight in kg. Defaults to `1`.
</ParamField>

<ParamField body="pickup_remarks" type="string">
  Instructions for the courier at pickup (consignor remarks). When omitted, the pickup address's
  stored remarks are used (or none if the address has none). Maximum 128 characters.
</ParamField>

<ParamField body="notes" type="string">
  Optional internal notes. Maximum 128 characters.
</ParamField>

## Response

On success, the API returns `201 Created` with the new shipment.

<ResponseField name="id" type="string" required>
  Shipment reference identifier (e.g., `P2604151234`).
</ResponseField>

<ResponseField name="status" type="string" required>
  Shipment lifecycle status. One of `pending`, `in_transit`, `delivered`, `fault`, or `cancelled`.
</ResponseField>

<ResponseField name="logistics_provider" type="string" required>
  Logistics provider. One of `go`, `dhl`, or `tof`.
</ResponseField>

<ResponseField name="tracking_number" type="string">
  External tracking number from the logistics provider. May be `null`.
</ResponseField>

<ResponseField name="origin" type="object">
  Pickup address. May be `null`.

  <Expandable title="address object">
    <ResponseField name="name" type="string" required>Company or location name.</ResponseField>
    <ResponseField name="street" type="string" required>Street name.</ResponseField>
    <ResponseField name="house_number" type="string" required>House number.</ResponseField>
    <ResponseField name="postal_code" type="string" required>Postal/ZIP code.</ResponseField>
    <ResponseField name="city" type="string" required>City.</ResponseField>
    <ResponseField name="country" type="string" required>ISO 3166-1 alpha-2 country code.</ResponseField>
    <ResponseField name="phone" type="string">Contact phone number. May be `null`.</ResponseField>
    <ResponseField name="email" type="string">Contact email. May be `null`.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="destination" type="object">
  Delivery address. Same structure as `origin`. May be `null`.
</ResponseField>

<ResponseField name="pickup" type="object">
  Scheduled pickup window. May be `null`.

  <Expandable title="pickup object">
    <ResponseField name="from" type="string" required>Start of pickup window as a UTC instant (ISO 8601 with `Z` suffix).</ResponseField>
    <ResponseField name="till" type="string" required>End of pickup window as a UTC instant (ISO 8601 with `Z` suffix).</ResponseField>
    <ResponseField name="timezone" type="string" required>IANA timezone of the pickup location (e.g., `Europe/Berlin`). Use to render `from` / `till` in pickup-location wall-clock.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="notes" type="string">
  Optional notes. May be `null`.
</ResponseField>

<ResponseField name="status_updates" type="object[]" required>
  Chronological lifecycle events from the logistics provider (oldest first). Each entry has a
  `status` (free-form provider-sourced label) and `time` (ISO 8601). Empty array immediately after
  creation; populated by the hourly sync as the provider reports events.
</ResponseField>

<ResponseField name="appointments" type="ShipmentAppointmentLink[]" required>
  Appointments linked to this shipment, oldest-link first. Each entry is `{ id, added_at }`;
  cross-reference each `id` against [Get Appointment](/api/appointments/get-appointment).
  Contains the appointment passed via `appointment_id` (if any) immediately after creation.
</ResponseField>

<ResponseField name="created_at" type="string" required>
  Creation timestamp (ISO 8601).
</ResponseField>

<ResponseField name="updated_at" type="string">
  Last update timestamp (ISO 8601). May be `null`.
</ResponseField>

## Error responses

| Status | Description                                                                                                     |
| ------ | --------------------------------------------------------------------------------------------------------------- |
| `400`  | Validation error — e.g., invalid date format, weekend date, pickup window too narrow, same-day cutoff exceeded. |
| `403`  | Forbidden — your API key does not have access to this operation or the location is outside your access context. |
| `404`  | Location not found or inactive, or `appointment_id` was provided but the appointment doesn't exist.             |
| `500`  | Internal server error.                                                                                          |
| `502`  | Logistics provider rejected the request. Includes the provider's error message.                                 |

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://anivahealth.com/api/v1/shipments \
    --header 'x-api-key: YOUR_API_KEY' \
    --header 'Content-Type: application/json' \
    --data '{
      "location_id": "b7e2d1f5-3c4a-4e8b-a2f1-9d0c1e2f3a4b",
      "appointment_id": "c9f3e2a1-7d6b-4c5e-b3a2-1f0e9d8c7b6a",
      "pickup_date": "2026-04-15",
      "pickup_time_from": "09:00",
      "pickup_time_till": "12:00",
      "notes": "Handle with care — temperature-sensitive samples"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 201 theme={null}
  {
    "id": "P2604154821",
    "status": "pending",
    "logistics_provider": "go",
    "tracking_number": null,
    "origin": {
      "name": "Aniva Berlin Mitte",
      "street": "Unter den Linden",
      "house_number": "42",
      "postal_code": "10117",
      "city": "Berlin",
      "country": "DE",
      "phone": "+4930987654321",
      "email": "berlin-mitte@anivahealth.com"
    },
    "destination": {
      "name": "LabClinic GmbH",
      "street": "Laborstraße",
      "house_number": "10",
      "postal_code": "80331",
      "city": "München",
      "country": "DE",
      "phone": null,
      "email": null
    },
    "pickup": {
      "from": "2026-04-15T07:00:00Z",
      "till": "2026-04-15T10:00:00Z",
      "timezone": "Europe/Berlin"
    },
    "notes": "Handle with care — temperature-sensitive samples",
    "status_updates": [],
    "appointments": [
      {
        "id": "c9f3e2a1-7d6b-4c5e-b3a2-1f0e9d8c7b6a",
        "added_at": "2026-04-15T07:00:00Z"
      }
    ],
    "created_at": "2026-04-15T07:00:00Z",
    "updated_at": null
  }
  ```

  ```json 400 theme={null}
  {
    "error": "pickup_date must be a weekday (Monday–Friday)"
  }
  ```

  ```json 404 theme={null}
  {
    "error": "Location not found or inactive"
  }
  ```

  ```json 502 theme={null}
  {
    "error": "Logistics provider error: Pickup on weekend/holiday not possible",
    "logistics_error_code": 2001
  }
  ```
</ResponseExample>
