---
title: Conventions
description: Design principles and naming patterns that make the Seamless OS API consistent and predictable.
---

The Seamless OS API keeps to the same design principles on every endpoint. Read these
conventions once, and the rest of the API behaves the way you expect.

## Identifier naming

**Specific identifier names.** An identifier field carries the name of its entity:
`subscriptionId`, `customerId`, `productOfferingId`. We do not use a generic `id` field, so a
payload never leaves the entity type in doubt.

**One name in every object.** The same entity always has the same identifier field name. You
can join and filter on that one name across every endpoint and every response.

### Common identifier patterns

| Entity           | Identifier Field    |
| ---------------- | ------------------- |
| Customer         | `customerId`        |
| Subscription     | `subscriptionId`    |
| Order            | `orderId`           |
| Product Offering | `productOfferingId` |
| Payment Link     | `paymentLinkId`     |
| Payment Session  | `paymentSessionId`  |
| Invoice          | `invoiceId`         |
| License          | `licenseId`         |

## Backward compatibility

The API changes continuously. This contract tells you which changes to expect at any time,
and which changes we treat as breaking.

### Changes to expect at any time

Your integration has to tolerate all of these:

- **New fields in a response.** Response objects are open. We add fields to them as the
  platform grows, and a field you never saw before can appear in any response.
- **New endpoints**, beside the existing ones.
- **New optional fields in a request body.** These never change what is already required.
- **New webhook event types**, and new fields in the payload of an existing one.

Your code has to do one thing for this: **ignore fields that you do not recognize**. If you
generate a client from our specification, examine how that client treats an unknown property.
Some generators reject an unfamiliar field outright. A routine addition on our side then
becomes a failed request on yours. Most generators have a flag for this.

### Changes we treat as breaking

A breaking change never reaches your integration unannounced. We pin your API key to a
revision, and we publish a breaking change as a new revision. Your key keeps its revision until
you move the pin. [Versioning](/api-reference/versioning.md) gives the full contract.

These are the changes we treat as breaking:

- We remove or rename a field, an endpoint, or a webhook event type.
- We make an optional request field required, or we narrow what a field accepts.
- We change the type or the meaning of an existing field.
- **We add a value to an existing enum.** A generated client turns an enum into a closed set
  of constants, so a new value fails to decode. This makes the addition breaking in practice,
  whatever the specification permits.

### Request bodies are strict

A request body is the mirror image of a response. We reject a body that carries a field the
endpoint does not define, and we do not ignore it. A misspelled property name gets a `400`
that names the offending field, not a value that disappears without a word.
