# API changelog

Octany has two API versions. The account setting picks the default, and
the `Octany-Version` header overrides it for one request. See
[integration.md#api-versions](integration.md#api-versions) for how to
choose. This page lists what differs between the versions and what
changed in both.

## Version 2

Version 2 describes the donor as a contact and leaves out the legacy
customer and the billing portal links. New accounts start on version 2.

| Area | Version 1 | Version 2 |
| --- | --- | --- |
| Donor on subscriptions and orders | `customer_id` and `customer`, referencing the legacy customer record. | `contact`: the full contact, the same shape as `GET /contacts/{id}`, including `metadata`. `null` when no contact is linked. |
| Billing portal links on subscriptions | `update_card_url`, `invoices_url` and `cancel_url`. | Left out. The billing portal will replace them. Until then, send donors to the [client portal](portal.md). |
| Webhook envelope | No `version` field. | `"version": 2` next to `name`. |

Everything else is the same in both versions: products, contacts,
webhook endpoints, errors, and every other subscription and order field.

The same subscription in both versions (shortened):

```json
// Version 1
{
  "id": 76963688,
  "customer_id": 519461363,
  "price": 9900,
  "status": "active",
  "update_card_url": "https://octanybilling.com/…",
  "invoices_url": "https://octanybilling.com/…",
  "cancel_url": "https://octanybilling.com/…",
  "customer": { "id": 519461363 }
}
```

```json
// Version 2
{
  "id": 76963688,
  "contact": {
    "id": 1042,
    "type": "person",
    "name": "Anna Persson",
    "email": "anna@example.com",
    "metadata": { "crm_id": "CRM-1001" }
  },
  "price": 9900,
  "status": "active"
}
```

## All versions

These changes are additive, so they apply to both versions.

- **`Octany-Version` header.** Send it to pick a version for one
  request. Every response returns it with the version used, and an
  unsupported value returns `400`.
- **Contact `metadata`.** Store your own IDs on a contact with `POST` or
  `PATCH /contacts`. Keys are merged, and `null` removes one. A change to
  `metadata` alone doesn't send `contact.updated`. See
  [integration.md#contacts](integration.md#contacts).
- **`subscription.updated` on price changes.** The event now also fires
  when the amount changes, whether in the portal, the admin UI or
  through a product price update. See
  [webhooks.md](webhooks.md#subscriptionupdated).

## Upgrading

Move one integration at a time. Version 1 keeps working while you do.

1. Send `Octany-Version: 2` from the integration and read `contact`
   instead of `customer_id` and `customer`. Match donors on `contact.id`,
   or on your own ID in `contact.metadata`.
2. Stop reading `update_card_url`, `invoices_url` and `cancel_url`. Link
   donors to the [client portal](portal.md) instead.
3. Accept the `version` field in webhook envelopes.
4. When every integration handles version 2, switch the account in the
   admin UI under **Settings → API keys** by clicking **API version**.
   Webhooks follow the account setting.
