Skip to main content
Anything that is not a GET needs two things beyond the credential: the write scope, and an Idempotency-Key.

The key is required, not offered

Moving a card runs Git. A client whose request timed out cannot tell “it failed” from “the answer got lost” — and the only way to find out is to ask again, which is exactly the thing that is not safe to do when asking again might merge a second time. An optional guard against a silent double merge is a guard the one caller who needed it did not use. So it is required on every write, including the ones that touch no repository, because a rule you have to remember when it matters is a rule you will not remember when it matters.
header
required
Any string of 16 to 255 characters, from A-Z a-z 0-9 _ . : -. Make it unique per attempt-you-mean: a run id, a job id, a hash of the thing that caused the write. Not a timestamp you regenerate on retry — that defeats it.

What each answer means

1

First time: it runs

The answer is stored under the key.
2

Same key, same request: it replays

You get the first answer back, with Idempotent-Replay: true, and nothing runs. This is the case the whole mechanism exists for.
3

Same key, different request: 409

A key used for two different requests is a bug in your code, and serving the other request’s answer would hide it behind a success.
4

Same key while the first is still running: 409

Wait for it. Running both would be the double merge with extra steps.
A failed attempt releases its key. If a write is rejected for a bad field, fix the field and send it again on the same key — you should not have to invent a new one to correct a typo.
Keys are kept for 24 hours, and are scoped to your credential: two integrations both choosing nightly are not the same request.

The credential signs what it does

A write credential is a member of the boards it reaches — it has a user of its own, the same way an agent does. So the card it creates says createdBy: the deploy script, its timeline reads status_changed → the deploy script, and a comment it posts is its own. That is the point of it. A board whose history says somebody moved a card is a board that cannot answer the only question worth asking after something goes wrong.

What it may do

Two gates, and they answer different questions.
403
A credential issued for reading only is told so: This credential was issued for reading only. Issue one with the write scope.
403
Per route, against the role this credential holds on the board in the header: That needs the member role or higher, and this credential holds viewer on workspace 83729280714017040.
Roles are the product’s own, so they mean here what they mean on screen. Creating a card or a label is a member’s; deleting a project, freezing a release and completing one are a maintainer’s.

Moving a card

The write that runs Git, and the one to read carefully.
Two facts, not one: the card moved, and these repositories merged. A caller acting on the second should not have to infer it from the first.
A refused promotion is 409, not 400. The request was fine and the world said no — conflicts, red checks, nothing to merge. The card stays exactly where it was, carrying the reason, and the message is the forge’s own words.
statusId comes from /v1/board, where each column carries its own id and the minRole it takes to move into it.

Releases

The half most worth automating, because these are the gestures a pipeline has reason to run on a schedule rather than by hand. promote answers with an outcome rather than failing: a release of twelve cards where nine moved and three were refused is news, not an error. The refusals are in the body, each naming its card and the repository that said no.

The rest

What a credential cannot do

Two writes exist in the product and are deliberately not on this API.
A proposal waits precisely because a person should look at it, and the provider is what enforces that. A credential that could approve one would be a way to route around the review by writing a script.
Handing out access to a board is the act every other permission rests on. A credential that can grant access is one whose own revocation no longer bounds what it did.
Both stay with a person and a session.