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

# Attach Appointments to Shipment

> Link one or more appointments to a shipment

Attach one or more appointments to this shipment. Idempotent — appointments already linked are
silently skipped.

The mutation rule (per appointment) is: the link can be created when EITHER

* the appointment is past blood-draw (`blood_drawn`), or
* the shipment was created less than 24 hours ago.

Outside that window the call is rejected with `409 Conflict` so historical records stay stable.

The same rule gates [Detach Appointments from
Shipment](/api/shipments/detach-appointments-from-shipment) and the inverse appointment-side
endpoints, so partners don't have to reason about direction.

## Request

### Path parameters

<ParamField path="id" type="string" required>
  Shipment reference ID (e.g., `P2604154821`).
</ParamField>

### Body parameters

<ParamField body="appointment_ids" type="string[]" required>
  Array of appointment UUIDs to attach. Must contain at least one item.
</ParamField>

## Response

On success, the API returns `200 OK` with the full appointment list for the shipment, oldest-link
first. Each entry has the same shape as [Get Appointment](/api/appointments/get-appointment).
Mirror of [Attach Shipments to Appointment](/api/appointments/attach-shipments-to-appointment),
which returns the post-mutation shipment list for the parent appointment.

## Error responses

| Status | Description                                                                                                                             |
| ------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Validation error — e.g., empty `appointment_ids` or invalid UUID.                                                                       |
| `403`  | Forbidden — missing scope, shipment outside access context, or appointment outside access context.                                      |
| `404`  | Shipment not found, or one or more appointments not found.                                                                              |
| `409`  | Mutation rule failed — at least one appointment is not past blood-draw and the shipment is older than 24 hours. Response lists the IDs. |
| `500`  | Internal server error.                                                                                                                  |

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://anivahealth.com/api/v1/shipments/P2604154821/appointments \
    --header 'x-api-key: YOUR_API_KEY' \
    --header 'Content-Type: application/json' \
    --data '{
      "appointment_ids": [
        "c9f3e2a1-7d6b-4c5e-b3a2-1f0e9d8c7b6a"
      ]
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  [
    {
      "id": "c9f3e2a1-7d6b-4c5e-b3a2-1f0e9d8c7b6a",
      "profile_id": "a3f1c2d4-8b7e-4f2a-9c1d-2e3f4a5b6c7d",
      "location_id": "b7e2d1f5-3c4a-4e8b-a2f1-9d0c1e2f3a4b",
      "scheduled_at": "2026-04-15T08:30:00Z",
      "status": "blood_drawn",
      "test_method": "practitioner",
      "created_at": "2026-04-01T09:45:00Z",
      "updated_at": "2026-04-15T08:30:00Z",
      "profile": {
        "id": "a3f1c2d4-8b7e-4f2a-9c1d-2e3f4a5b6c7d",
        "first_name": "Maria",
        "last_name": "Schmidt",
        "email": "maria.schmidt@example.com",
        "date_of_birth": "1985-03-22",
        "sex": 2
      },
      "panels": [],
      "individual_biomarkers": [],
      "shipments": [
        {
          "id": "P2604154821",
          "added_at": "2026-04-15T08:30:00Z"
        }
      ]
    }
  ]
  ```

  ```json 409 theme={null}
  {
    "error": "Cannot attach appointments outside the allowed window — each appointment must be past blood-draw or the shipment must be less than 24 hours old. Blocked: c9f3e2a1-7d6b-4c5e-b3a2-1f0e9d8c7b6a"
  }
  ```
</ResponseExample>
