Skip to content

Authentication

An API key is the credential your pipeline sends instead of signing in. It belongs to your organization and not to a person, so it keeps working when whoever created it leaves. It stops working on a date chosen when it was created.

Put it in the Authorization header, after Bearer:

authenticated-call.sh
curl --silent --show-error --fail-with-body \
-H "Authorization: Bearer $FACTEUR_API_KEY" \
https://api.facteur.eu/inboxes

A key starts with fk_. The API turns away anything else before it looks anything up.

Creating, changing and revoking a key are done by a person who is signed in to the Facteur app, in Settings, then API keys, and only by an owner or an administrator. No key can make or end a key, its own included, and the API has no route for it.

You choose a duration of 30, 90, 180 or 365 days when you create a key, and every key expires. The key is shown once, when it is created. Facteur keeps a hash of it, so nobody can show it again. After a revocation, the next call made with that key is refused with API_KEY_REVOKED.

A key holds one or more of four permissions, in two families:

Permission What it opens
ws:read Read the inboxes, the messages and the requests for an SMS number of the workspaces the key reaches.
ws:write Everything ws:read does, and create, change and delete inboxes and extractors, and ask for an SMS number or take the request back.
org:read Read the structure of the organization: its workspaces and their members, its capacity and the destinations of its alerts.
org:write Everything org:read does, and create and change workspaces and their members.

Inside a family, writing includes reading. The two families never include each other: a key that holds org:write alone creates workspaces and reads no message.

Every operation of the reference names the permission it needs. A key that lacks it gets a 403 whose code is API_KEY_PERMISSION_MISSING, and whose permission member names the permission that was missing:

permission-missing.sh
curl --silent --show-error --include \
-X POST \
-H "Authorization: Bearer $FACTEUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "A workspace"}' \
https://api.facteur.eu/workspaces

With a key that holds ws:read only, this call answers 403, with a WWW-Authenticate header that carries error="insufficient_scope" and the missing permission as scope.

A workspace groups inboxes and decides who reaches them. When you create a key, you pick the workspaces it reaches, or every workspace, including those created later. A workspace the key does not reach answers 404, as if it did not exist.

None of these has a route on the API, whatever permissions the key holds:

  • invite a person to an organization;
  • pay, change the plan or the spending cap, or read the invoices;
  • create, change or revoke an API key;
  • create, change or delete the destinations of the alerts. A key can only list them.

An API key never deletes a workspace either: DELETE /workspaces/{slug} always answers 403 with the code API_KEY_CANNOT_DELETE_WORKSPACE. A person deletes it from the app.

Read a refusal that says how to authenticate

Section titled “Read a refusal that says how to authenticate”

A 401 carries a WWW-Authenticate header. It points at the document that describes how to present a key:

WWW-Authenticate: Bearer realm="Facteur API",
resource_metadata="https://api.facteur.eu/.well-known/oauth-protected-resource"

A key that was presented and refused adds error="invalid_token". Three codes tell apart the reasons for a refusal, because each one calls for a different fix:

Code What happened What you do
API_KEY_UNKNOWN The key never existed. Check what your pipeline actually sends.
API_KEY_REVOKED A person revoked it. Create a new key.
API_KEY_EXPIRED It is past its date. Create a new key, and do it before the date next time.

A request with no key at all answers UNAUTHENTICATED. The errors guide lists every code.