Versions and the beta marker
The version is in the address (/api/v1/) and in the API description
(1.0.0-beta). While the API is in beta, every response carries an
x-goosy-api: beta header.
Beta does not mean anything can change at any moment. A change either adds
something — a new action, a new optional argument, a new field in an answer, a
new refusal code — or it is deprecated first and removed later (see
Deprecations). Write your code to ignore fields it does not
know, and a new field will never break it.
Request ids
Send anx-request-id header with your own id for the call, and you get the
same id back:
- Every response carries one, refusals included. If you send none, or one we cannot use, we generate one and send that back instead.
- An id is 1–128 characters from
A–Z a–z 0–9 . _ : -, starting with a letter or a digit. - Log it. The id is recorded on the activity trail for the call, so quoting it to support finds your call without a timestamp hunt.
One error shape
Every failure you can read hasok: false, a code and a message at the top
level — whether the request was turned away at the door or the action itself
declined:
ok, then on code. The status tells you which layer answered:
Refusals at the door also carry the same values in a nested
error object.
That object is deprecated: read the top-level fields. Every
code is listed in Errors and refusals.
Rate-limit headers
Every call that counted against your key’s per-minute allowance tells you where you stand:
Slow down when
RateLimit-Remaining gets low, rather than waiting for a 429.
A 429 adds Retry-After. Very rarely a response carries none of these three —
that means we could not count the call, and we let it through rather than
refuse you for our own fault. More in Rate limits.
Retrying safely: Idempotency-Key
A network can fail after an action ran but before you heard back. To retry
without doing the work twice, send an Idempotency-Key header with a key you
choose, and send the same key when you retry:
- The retry gets the first result back instead of a second table.
- A key is 1–200 visible characters with no spaces, and it is honoured for at least 24 hours.
- The API reference shows the header on every action that takes one, and
marks it required on an action that needs a key. On an action that does not, a key is refused with
tenant_api.idempotency_unsupportedand nothing runs — check whether the first call landed before you retry it. - Sending the key in the body as
idempotency_keystill works, but it is deprecated on the API. If you send both, they must match (tenant_api.idempotency_key_conflictotherwise).
idempotency_key as an
argument.
Paging through a list
A list action takeslimit and answers next_cursor while there is more. Pass
it back as cursor, with the same filters, to get the next page:
next_cursor is missing, you have the last page. Treat the cursor as an
opaque string: do not build or edit one. A cursor used with different filters
is refused with invalid_arguments; start again without it. content.status
also still answers truncated, which is deprecated in favour
of next_cursor. Searches (knowledge.search, library.search) answer their
best matches and have no pages; narrow the query instead.
Rotating a key
keys.rotate replaces the key that makes the call with a new one. It takes two
calls, like other actions that change who can use something:
- Call it with an optional
overlap_hours(default 24, at most 168). You get aconfirmation_idback and nothing changes yet. - Call it again with the same key, the same
overlap_hoursand theconfirmation_id. The answer carries the new key inkey. It is shown once, so store it straight away.
overlap_hours, then stops with the ordinary
401. Use the overlap to deploy the new key everywhere the old one was. A
confirmation sent with any other key is refused. Keys for a managed site are
rotated by the platform and refuse this action.
A confirmation is used up the moment it is accepted, so it can never make two
new keys. If the rotation then fails (keys.rotate_failed), nothing changed:
call again with no confirmation_id to start a fresh one. In the rare case the
answer is keys.rotate_successor_not_withdrawn, a new key with the prefix the
message names may still be active — revoke it in Settings › API & MCP. Your
current key is unchanged.
Deprecations
When something you can send or read is going away, we:- announce it here and in the changelog, with the date it may be removed;
- mark every response to a call that uses it — or whose answer carries it,
like
truncatedoncontent.status— with three headers —Deprecation(when it was deprecated),Sunset(the earliest removal date) andLink(this section); - keep it working for at least 90 days, and never remove it before the sunset date.