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

# Reconcile your roster

> POST /v1/partners/sponsorships/reconcile — a safety net that reconciles DSS seats against your authoritative active-member list.

<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/reconcile
Authorization: Basic <base64(client_id:client_secret)>
Content-Type: application/json
```

Your integration should [provision](/sponsorships/provision) a member the moment
they become eligible and [remove](/sponsorships/remove) them the moment they
lapse. This endpoint is the **safety net** for the times a webhook is missed: you
send DSS the full list of members you *currently* consider active, and DSS
reconciles its live seats against it — cancelling seats you no longer list and
reporting members you have that DSS never provisioned.

## Request

| Field                | Type       | Default | Notes                                                                                                                                                                                                     |
| -------------------- | ---------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `active_refs`        | `string[]` | —       | Your authoritative list of currently-active member identifiers. Each is matched against a seat's **email** and its **`external_ref`** (a seat survives if either matches). **An empty list is rejected.** |
| `apply`              | `boolean`  | `false` | When `false` (default) this is a **dry run** — the diff is returned and nothing is cancelled. Set `true` to actually cancel.                                                                              |
| `max_cancel`         | `integer`  | —       | Optional explicit ceiling on how many seats a single run may cancel.                                                                                                                                      |
| `override_threshold` | `boolean`  | `false` | Bypass the mass-cancel safety guard (see below).                                                                                                                                                          |

<Warning>
  **Empty `active_refs` returns `400`.** This is deliberate — a truncated or empty
  export must never be read as "cancel everyone". Always send your complete active
  list.
</Warning>

## Safety guards

Because this endpoint *cancels* seats, two guards protect against a bad payload:

* **Empty roster → `400 invalid_request`.**
* **Mass-cancel threshold.** If a run would cancel more than `max_cancel`, or
  (by default) more than 20% of your active seats *and* more than 10 seats, DSS
  **refuses to apply** and returns the diff with `threshold_exceeded: true`. Send
  `override_threshold: true` only once you've confirmed the drop is intended.

## Response

`200 OK`.

| Field                | Type       | Notes                                                                                                                                                                  |
| -------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `active_seats`       | `integer`  | Live seats DSS holds for you right now.                                                                                                                                |
| `to_cancel`          | `object[]` | Seats absent from `active_refs` — `{ sponsorship_id, email }`.                                                                                                         |
| `missing_refs`       | `string[]` | Identifiers you sent that have **no** live DSS seat — report only; DSS never auto-provisions from a reconcile. Re-[provision](/sponsorships/provision) these yourself. |
| `applied`            | `boolean`  | Whether cancellations were actually performed.                                                                                                                         |
| `cancelled_count`    | `integer`  | Number of seats cancelled (`0` on a dry run or a blocked run).                                                                                                         |
| `threshold_exceeded` | `boolean`  | The mass-cancel guard tripped; nothing applied without an override.                                                                                                    |

Each applied cancellation behaves exactly like [removing a seat](/sponsorships/remove):
the member is downgraded to Free, you receive a prorated credit, and tracking is
paused best-effort.

## Recommended usage

Run a nightly reconcile: first with `apply: false` to review the diff, then with
`apply: true` once your export looks right. Keep sending your **complete** active
list every time — the endpoint only ever cancels seats that are missing from it.
