# Versioning and deprecation

> The promise to partners: what counts as a change, how we version, how long you get when something is deprecated and how you find out.

- Page in the portal: https://developers.rivr.io/versioning

We are Rivr. You are the partner: a journal system, a platform or a clinic that calls the API with its own key or token.

## 1. What the promise covers

The promise covers:

- `/api/public` on `api.rivr.io`. `/api/public` also answers today on other Rivr host names, for example `rivr.io`. If you call it there, the promise applies there too, and we give notice under section 4 before it stops answering there;
- the oldest API, from Payzmart: every path on `api.payzmart.se` and `payzmart-api.rivr.io`, for example `/CreateOrder`, `/CreateCredit`, `/RefundPayment`, `/PartialRefundPayment`, `/GetInstallationInfo`, `/GetCompany` and the SOAP service `/server`;
- webhooks we send to your `callbackUrl` or to your organisation's endpoints: the body, the headers (`Rivr-Signature`, `Rivr-Webhook-Id`), the event types and the retry schedule;
- the error codes and the error shape: on `/api/public` the error body as it looks today (section 2, breaking change 9);
- how you get a token (token address, grant, parameters) and which capabilities an operation requires.

The sandbox (`api.test.rivr.io`) follows the same contract. New things can reach the sandbox before production. A deprecated path has the same shutdown date in both environments.

The promise does not cover:

- operations marked **Preview** in the reference (see section 3);
- the developer portal's interface and tools, for example the `rivr` CLI. Changes to them are also in the changelog;
- paths that are not in the current reference and that no partner has called in the last 90 days. If a partner has called the path, the promise applies, even if the path is not in the reference.

See also: [The API reference](https://developers.rivr.io/reference.md)

## 2. Breaking and non-breaking changes

### Breaking

A change like this is made only through a deprecation under section 4:

1. A path, method, parameter, header or field is removed or renamed.
2. A field changes type, format, unit or meaning. Examples: a string becomes a number, kronor become öre, or a date changes time zone.
3. The API accepts less than today. Examples: an optional parameter becomes required, a new required field in the request, a shorter maximum length, fewer allowed values or stricter validation that rejects a request that succeeds today.
4. An existing outcome gets a different status code, a different error code (`errorCode` on `/api/public`) or a different error shape.
5. Something we send today stops being sent, for example an enum value, an event type or a header in the response or in a webhook.
6. The same call gives a different result than today because a default value, a sort order, a page size or a filter has changed.
7. Authentication changes so that your integration has to do something. Examples: a new token issuer, a new audience, a new capability for an existing operation, or a key or token that stops being valid.
8. Webhook delivery changes so that the receiver has to adapt. Examples: a new signature scheme, fewer retries, a shorter wait for a response before we give up, or a changed body.
9. **On /api/public the quirks are part of the contract.** A behaviour you can notice does not change without a deprecation. That also applies when the behaviour differs from the documentation. `/api/public` has no `code`. Its errors carry `errorCode`, which can be missing, and `message`, and some errors come with no body at all. So we do not change the text of errors (`message`) or the order of fields in JSON without a deprecation either. If `/api/public` gets a `code`, it is stated in the changelog. From that day you act on `code` there too, but the text is still not changed without a deprecation.

### Non-breaking

A change like this can go out at any time and is in the changelog no later than the same day:

1. A new path, method or resource.
2. A new optional parameter or header in the request, for example `Idempotency-Key`.
3. A new field in a response, in an error body or in a webhook body.
4. A new header in the response or in a webhook, for example `Rivr-Request-Id`, `Rivr-Webhook-Id`, `Deprecation` and `Sunset`.
5. A new error code for a new outcome, for example in a new operation.
6. Changed human-readable text and changed documentation. This does not apply to the text of errors on `/api/public` (breaking change 9).
7. A changed order of fields in JSON and changed values in cursors. The order of fields does not apply to `/api/public` (breaking change 9).
8. A higher limit on call rate, a longer timeout or more retries.
9. A path is hidden in the reference but keeps working.

### Non-breaking with advance notice

These changes do not break the contract, but they can break an integration that does not follow section 9. They are therefore in the changelog **at least 30 days before** they go out:

1. A new value in an existing enum field in a response or a webhook, for example a new order status or a new payment method.
2. A new event type on an existing delivery path, for example on `callbackUrl`.
3. A new or lower limit on call rate. If any partner's traffic in the last 90 days has reached the new limit, we contact that partner directly at least 30 days before the limit takes effect.

If we are unsure which group a change belongs to, we treat it as breaking.

The limits on call rate that apply today are on the Rate limits page.

See also: [Rate limits](https://developers.rivr.io/rate-limits.md)

## 3. How we version

- **/api/public has no version number.** It changes only by additions and is deprecated path by path under section 4.
- **Preview.** An operation marked Preview in the reference can be changed or removed with 30 days' notice in the changelog. It is for trying out, not for production. When the operation becomes stable, the changelog says so, and from that day the whole promise applies.

## 4. Deprecation: at least 12 months

1. **The replacement comes first.** Before we give notice, the replacement is in production, documented and with a guide for moving. If a feature is shut down with no replacement at all, the notice gives the reason.
2. **The notice** is given on the same day in the changelog, in the headers, in the reference and through direct contact (section 5).
3. **The shutdown happens no earlier than 12 months after the notice**, that is, no earlier than the same calendar day a year later. The date is in the `Sunset` header and in the changelog from the first day.
4. **The date can be moved later, never earlier.** If we move it, you hear about it the same way as the notice.
5. **Reminders.** Six months, three months, one month and one week before the shutdown we contact again the partners that still call the path.
6. **Until the shutdown the path works as before.** It gets no new features, but bugs and security flaws are fixed.

## 5. How you find out

1. **The changelog** at `developers.rivr.io/changelog`. It lists every change to the contract. Each entry gives the type (breaking, deprecation, advance notice or non-breaking), the surface (`/api/public` or webhooks), what changes, what you need to do and when. Each entry has an address of its own, and you can subscribe to the changelog.
2. **Direct contact.** We contact every partner that has called the deprecated path in the last 90 days. We see that in our own server logs, so you do not need to have signed up anywhere. The contact goes to your organisation's administrators in the portal and to the technical contact you have given us. If a clinic calls with its own key, we contact the clinic, and if we know which system the calls come from, we contact the system's supplier too.
3. **Headers in every response** from the deprecated path (section 6).
4. **The reference** marks the path as deprecated, with the date and the replacement.

If you have questions about a deprecation we answer within one working day. The way to contact us is in the portal.

See also: [The changelog](https://developers.rivr.io/changelog.md), [Subscribe (Atom)](https://developers.rivr.io/changelog.atom), [The API reference](https://developers.rivr.io/reference.md), [Support](https://developers.rivr.io/support)

## 6. The headers

From the notice to the shutdown, every response from a deprecated path carries three headers, error responses too:

| Header | Standard | Value |
|---|---|---|
| `Deprecation` | RFC 9745 | The time of the notice, as a date in Structured Fields format: `@` followed by Unix time in seconds |
| `Sunset` | RFC 8594 | The earliest time of the shutdown, as an HTTP date. Never earlier than 12 months after `Deprecation` |
| `Link` | RFC 8288 | The changelog entry, with `rel="deprecation"` and `rel="sunset"` |

An invented example: the path `GET /api/public/exempel/{id}` is deprecated with notice on 1 February 2027 and shutdown no earlier than 1 February 2028.

```http
HTTP/1.1 200 OK
Content-Type: application/json
Deprecation: @1801468800
Sunset: Tue, 01 Feb 2028 08:00:00 GMT
Link: <https://developers.rivr.io/changelog/2027-02-01-exempel-utfasning>; rel="deprecation"; type="text/html", <https://developers.rivr.io/changelog/2027-02-01-exempel-utfasning>; rel="sunset"; type="text/html"
```

- The headers apply to the whole path. **If only a field or a parameter is deprecated, they are not set.** It is then in the changelog and in the reference, and we contact every partner that has called the path.
- **Webhooks carry no deprecation headers.** If a field or an event type in a webhook is deprecated, it is in the changelog, and we contact every partner that has received it in the last 90 days.
- Have your integration log or alert when a response carries `Sunset`. Then you never miss a notice.

## 7. After the shutdown

A path does not disappear silently. It answers `410 Gone` with `application/problem+json` and a link to the changelog entry and the replacement.

See also: [The changelog](https://developers.rivr.io/changelog.md)

## 8. Exception: security and law

A change that closes a security hole, for example one where a caller can reach another clinic's data, can go out with shorter notice than 12 months. The same goes for a change required by law or an order from an authority. The change still never goes out silently:

- When we can, we first measure which calls would be refused, and contact those partners before we start refusing.
- The changelog gets an entry no later than the same day the change goes out. If a description in advance would reveal the hole, we describe it afterwards.

If we block an individual key that has leaked or is being abused, that is not a change to the API, and this policy does not apply. We then contact you directly.

## 9. What we expect of your integration

- Ignore fields and headers you do not recognise.
- Handle unknown enum values and event types without crashing, for example by logging them and moving on.
- `/api/public` has no `code` yet. Act on the status code and on `errorCode` when it is present.
- Do not interpret the contents of a cursor.
- Follow the changelog, or log the `Sunset` header.
- Keep the list of your organisation's administrators in the portal up to date, so that notices reach the right person.
