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

# Provision a seat

> POST /v1/partners/sponsorships — auto-provision a crew member into a sponsored Premium seat.

<Note>
  **Restricted — requires a sponsorship program.** See the
  [Sponsorship API overview](/sponsorships/overview) for access and auth.
</Note>

```http theme={null}
POST /v1/partners/sponsorships
Authorization: Basic <base64(client_id:client_secret)>
Content-Type: application/json
```

Auto-provisions one crew member into a sponsored Premium seat in a single call
(just-in-time). DSS creates or reuses the account, attaches the vessel by IMO,
turns on Premium, and starts billing the seat to you. The member is `active`
on success.

## Request body

| Field          | Type               | Required | Notes                                                                                   |
| -------------- | ------------------ | -------- | --------------------------------------------------------------------------------------- |
| `email`        | string             | Yes      | Crew member's email. Normalised (trimmed, lower-cased) and used as the idempotency key. |
| `first_name`   | string             | Yes      | Given name for the account.                                                             |
| `last_name`    | string             | Yes      | Family name for the account.                                                            |
| `position`     | string             | Yes      | Crew rank/role, e.g. `Chief Stewardess`.                                                |
| `vessel_imo`   | string             | Yes      | Exactly 7 digits (`^\d{7}$`). The vessel to track.                                      |
| `phone`        | string             | No       | E.164, e.g. `+447700900123`.                                                            |
| `vessel_name`  | string             | No       | Display name; helps when the IMO is new to DSS.                                         |
| `join_date`    | string (date-time) | No       | ISO 8601. When the member joined the vessel.                                            |
| `external_ref` | string             | No       | Your own opaque reference. Echoed back on the roster for reconciliation.                |

```json theme={null}
{
  "email": "jane@example.com",
  "first_name": "Jane",
  "last_name": "Doe",
  "position": "Chief Stewardess",
  "vessel_imo": "9074729",
  "vessel_name": "MY Example",
  "phone": "+447700900123",
  "join_date": "2026-07-01T00:00:00Z",
  "external_ref": "ref-0042"
}
```

## Response

`201 Created` when a new seat is provisioned; `200 OK` on an idempotent replay
(an open seat already existed for this email — see below).

| Field             | Type           | Notes                                                                                                                                                                                     |
| ----------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sponsorship_id`  | string         | The seat id. Use it with the [get](/sponsorships/reconciliation#get-one-seat) and [remove](/sponsorships/remove) endpoints.                                                               |
| `status`          | string         | Seat [lifecycle status](/sponsorships/overview#seat-lifecycle) — typically `active`.                                                                                                      |
| `vessel_resolved` | boolean        | `false` when the IMO didn't match a known vessel. This is a **soft failure**: the seat is still created and the member still gets Premium; tracking attaches once the vessel is resolved. |
| `expires_at`      | string \| null | The member's sponsored term end (`activated_at` + the program term).                                                                                                                      |

```json theme={null}
{
  "sponsorship_id": "665f00000000000000000042",
  "status": "active",
  "vessel_resolved": true,
  "expires_at": "2027-07-24T09:00:00Z"
}
```

<Note>
  **`vessel_resolved: false` is not an error.** A 7-digit IMO that DSS hasn't
  seen yet still yields a provisioned, Premium seat. Pass `vessel_name` to help,
  and DSS resolves and back-fills tracking asynchronously. Poll the seat on the
  [roster](/sponsorships/reconciliation) if you want to confirm resolution.
</Note>

## Idempotency

Provisioning is idempotent **per email within your program**:

* If the email already holds an **open seat** (`active`), the call returns that
  existing seat with `200` and does **not** create a second seat or a second bill.
* Otherwise a new seat is created and returned with `201`.

You may also send an optional `Idempotency-Key` header for your own
tracing/retry safety:

```http theme={null}
Idempotency-Key: 5f3c...your-uuid...
```

The header is accepted for convenience, but **the email is the primary
idempotency key** — an open seat for the same email is never duplicated,
regardless of the header value.

## Errors

| Status    | `type`                                                       | When                                                           |
| --------- | ------------------------------------------------------------ | -------------------------------------------------------------- |
| 400 / 422 | [`invalid_request`](/errors/invalid_request)                 | Missing/invalid field, e.g. `vessel_imo` not exactly 7 digits. |
| 401       | [`invalid_token`](/errors/invalid_token)                     | Missing or bad Basic credentials.                              |
| 403       | [`insufficient_scope`](/errors/insufficient_scope)           | The partner account is suspended.                              |
| 409       | [`email_already_premium`](/errors/email_already_premium)     | The email already self-pays for Premium — nothing to sponsor.  |
| 409       | [`sponsorship_cap_reached`](/errors/sponsorship_cap_reached) | The program's seat cap is full. (Programs may be uncapped.)    |

## Related

* [Reconcile your roster](/sponsorships/reconciliation)
* [Remove a seat](/sponsorships/remove)
* [`email_already_premium`](/errors/email_already_premium)
* [`sponsorship_cap_reached`](/errors/sponsorship_cap_reached)
