Core concepts
Versioning & deprecation
URI versioning under /v1 and how breaking changes are handled.
The API is versioned in the URL so an integration keeps working unchanged for the life of a version. There is one public version today — v1 — and every route lives under it.
Where the version lives
The version is a path segment (/v1) sitting after the /api global prefix. It is not a header and not negotiated — the version you call is the version you get.
https://gulfpay-production.up.railway.app/api/v1/customers
└┬┘
the API major versionPin the full base URL — https://gulfpay-production.up.railway.app/api/v1 — in your client configuration. When a future major version ships it will be served under a new segment (/v2) alongside v1; nothing about your v1 calls changes.
What counts as a breaking change
Within v1, changes are made in a backward-compatible way. A new major version is minted only for changes that could break a well-behaved client. Concretely:
| Backward-compatible (no version bump) | Breaking (new major version) |
|---|---|
| Adding a new endpoint or resource | Removing or renaming an endpoint |
| Adding a new optional request field | Making a previously optional field required |
| Adding a new field to a response | Removing or renaming a response field |
| Adding a new optional query parameter | Changing the type or meaning of an existing field |
| Adding a new enum value or error code | Changing the shape of the response envelope |
Write tolerant clients
Deprecation policy
When a capability is slated for removal it is first deprecated, not deleted. During the deprecation window the old behaviour keeps working while you migrate. Deprecations and their timelines are announced in the changelog. As a rule of thumb:
- A deprecated field or endpoint continues to function within its version.
- Removal happens only at a major-version boundary, never inside
v1. - The changelog is the record of what changed and when — check it before upgrading.
Server errors never leak internals