Skip to content
Facteur
FRGet started

Type at least two characters.

Create an API key and wire up your test suite

Create a key, use it from CI, rotate it without downtime and revoke it. What it reaches, and what it will never reach.

An API key lets your tests call the API with no browser and no session. It belongs to the organization, which means it survives the departure of whoever created it: your CI does not break because somebody changed jobs.

You have to be an owner or an administrator of the organization to create one.

Create a key

Open Settings → API keys → Create a key and fill in four fields.

  1. A name. It is what will tell you which one to revoke in six months: “GitHub CI”, “Camille’s staging”.
  2. What it can do. Read-only by default, which is what a test suite needs. A second checkbox opens workspace management, for a provisioning script.
  3. Where. If you say nothing, the key only reaches your main workspace. The response always reminds you of the scope you got.
  4. A duration. 90 days by default, one year at most.

The secret is shown once only, right after creation. We keep nothing but a hash of it: neither you nor we can retrieve it afterwards. Copy it straight into your CI’s secrets.

Use it

One Authorization header, and that is all:

curl -H "Authorization: Bearer fk_your_key" \
  https://api.facteur.eu/v1/inboxes

The Basic form works too, with the key as the username and an empty password: that is what some SDKs built for other platforms send.

Do not send a session cookie alongside a key. The request is refused with AMBIGUOUS_CREDENTIALS rather than resolved arbitrarily: two identities in one request would give you a test that proves something about the wrong one.

Allow 600 requests per minute per key. Past that, 429 KEY_RATE_LIMITED.

Every route, its scope and its refusals are listed in the API reference, on developers.facteur.eu. It opens in your language, and it is generated from the specification the API is held to.

Choose the scope

A key answers two questions separately, which lets you hand out little at a time.

What it can do, in four scopes and two families:

ScopeWhat it opens
ws:readRead the messages of the workspaces it targets
ws:writeCreate and delete inboxes there
org:readList the workspaces, and see who reaches each one
org:writeCreate one, rename it, tag it, and add or remove the colleagues who reach it

Where it can do it: all your workspaces, or only the ones you name.

Write implies read within a family, and nothing crosses families. org:write therefore gives no access to your mail: a script that provisions workspaces has no business reading the messages inside them.

If you choose “all workspaces”, the scope also covers the ones you create later. A list frozen at creation would be a key that silently stops covering your new workspaces.

What a key never reaches

Whatever its scope.

What the key triesThe refusalWhat you do
Create or revoke a keyRoute unreachableGo through the application. A stolen key that rotates itself would make its own revocation meaningless
Touch your account: password, second factor, passkeysRoute unreachableA leaked key does not take the account
Write while it is read-only403 SCOPE_INSUFFICIENTThe response names the missing scope and the ones the key carries
List workspaces without org:*403 SCOPE_INSUFFICIENTCreate a key with org:read
Bring somebody into the organization403 KEY_CANNOT_INVITEInvite from the application. See Members and seats
Delete a workspace403 KEY_CANNOT_DELETE_WORKSPACEDelete from the application: the operation reassigns usage history and needs somebody to read it
Read the mail of a workspace outside its scope404A key targeting “staging” does not read the main workspace. Same boundary as members, see Workspaces

A support session cannot create a key either, even with your explicit consent: the key would afterwards be indistinguishable from one you had created yourself.

Rotate without downtime

Rotating creates a fresh key and lets the old one live for 24 hours. Deploy the new secret, watch a green build go by, and the old one goes out on its own. A rotation that cuts is a rotation nobody performs.

An already revoked key cannot be rotated: that would keep it alive for a few more hours, which would undo the revocation.

Revoke

Immediate, with no cache window: the next call fails, including one from a pipeline already running.

Before revoking, read the “last used” column: it tells you whether the key is still in service.

Afterwards, the refusal separates three cases, because the actions they call for are different:

CodeWhat it meansWhat you do
KEY_REVOKEDSomebody withdrew itCreate a new one
KEY_EXPIREDIt reached its dateRotate it
KEY_UNKNOWNThis key never existedCheck what your CI is sending

Delete a workspace a key targets

Refused, with 409 WORKSPACE_HAS_ACTIVE_KEYS and the names of the keys that block it.

Two possible moves before trying again: revoke the key, or remove that workspace from its scope. An already revoked or expired key blocks nothing, since it opens nothing.

Provision one workspace per branch

That is what org:write is for:

# Open a workspace for the current branch
curl -X POST https://api.facteur.eu/v1/workspaces \
  -H "Authorization: Bearer fk_your_key" \
  -H "content-type: application/json" \
  -d '{"name": "staging-PR-1234"}'

Two things to know:

  • The workspace it creates is not in the key’s scope. A key does not widen itself. If your tests have to read the mail of that new workspace, target “all workspaces” when you create the key.
  • The plan’s ceiling applies. A plan that sells only one workspace answers 402, naming the plan from which it becomes possible.

Manage who reaches a workspace

A key carrying org:write can list a workspace’s members, add one and remove one.

That brings nobody into your organization. The person you name has to be a member already; anybody else is refused with NOT_AN_ORGANIZATION_MEMBER. What changes is which workspaces a colleague already present can open, and it uses no seat.

Inviting remains the act a key never performs.

Known limits

  • No IP address restriction. An allowlist, for runners that leave through a fixed address, is announced on the screen as coming.

Checked on Is this article wrong or incomplete?