This page covers the conventions every Gozem API shares: how versioning works, how list endpoints paginate, how errors are returned, and how rate limiting behaves. They apply the same way across all services.
Versioning
The platform uses URL path versioning. Each request carries a version segment in the path, right after the service prefix. Requests without a version are not supported.
The current version is v1, the current and stable version. Use it for all integrations unless told otherwise.
Versioning follows a major-version model, and within a major version backward compatibility is preserved. We will not remove an existing endpoint or field, and we will not change the meaning of an existing field. We may add new optional fields, new endpoints, and new enum values, so write your integration to tolerate fields and enum values it does not recognize. Breaking changes only ever land in a new major version.
When a version is deprecated it is still available but scheduled for removal, and a migration window is provided before it is retired. A retired version is no longer accessible.
Pagination
List endpoints return results in pages so a single response stays a manageable size. Pagination is offset-based: you ask for a number of items and an offset into the full set.
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
number | 20 | Number of items to return |
offset |
number | 0 | Number of items to skip before the page starts |
Both are optional; defaults apply when you omit them. Some endpoints enforce a maximum limit, noted on the endpoint itself.
A paginated response returns the page of data alongside a meta object describing the full set:
{
"message": "Ok",
"data": [],
"meta": {
"total": 42,
"limit": 20,
"offset": 0
}
}
data holds the items for the current page. meta.total is the total number of items available, and meta.limit and meta.offset echo what was applied. You are on the last page once offset + limit is at or beyond total; to read the next page, add limit to offset. Request only what you need, and where you are tracking changes rather than browsing, prefer webhooks over repeatedly paging through lists.
Error responses
When a request fails, the API returns a standard HTTP status code and a JSON body in a consistent shape across every service:
{
"error": "BadRequestError",
"message": "A human-readable description.",
"code": "a_stable_code",
"details": null
}
| Field | Type | Description |
|---|---|---|
error |
string | The HTTP error class name. Informational only; do not branch on it. |
message |
string | A human-readable description. It may be reworded or localized; do not branch on it. |
code |
string | A stable, machine-readable code. Branch on this. |
details |
object | array | null | Optional structured context, such as the list of failing fields on a validation error. |
Build your error handling around the code field. The error field is the HTTP class name and is there for readability; message is human-facing text that can change or be translated. Neither is a stable contract; code is. Handle a code you do not recognize gracefully, for example by falling back to the HTTP status, rather than failing hard.
Rate limiting
All API requests are rate limited to keep the platform stable and fair across partners. Limits are enforced per client and per environment, and apply across all endpoints unless stated otherwise. The default is 100 requests per minute, though this may vary with your integration, environment, or agreed usage profile.
Every response carries your current rate-limit state in headers, so you can pace requests before you hit the limit:
| Header | Description |
|---|---|
X-RateLimit-Limit |
Maximum requests allowed in the window |
X-RateLimit-Remaining |
Requests left in the current window |
X-RateLimit-Reset |
Unix timestamp when the window resets |
When you exceed the limit, the API returns 429 with the code rate_limit_exceeded, and may include a Retry-After header with the seconds to wait. When you get a 429, wait for the window to reset before retrying rather than resending immediately, and prefer Retry-After when it is present. More importantly, design the integration so you rarely reach the limit:
- Spread requests over time instead of sending bursts.
- Cache data that does not change often.
- Use webhooks for updates instead of polling on a timer.
- Prefer list and filter endpoints over many single-resource calls.
If a production integration needs more throughput, the limit can be reviewed. Contact support with your use case and your expected traffic pattern and volume.