Skip to content
einvoicing.dev

API/Keys

Create an API key

POST/v1/keys· API key

Creates a key on the calling key's account. The secret appears in this response and nowhere else, ever, so the request cannot be replayed: see "Retries". An account can hold several active keys at once, which is how a key is rotated without downtime. Create the new one, deploy it, then revoke the old one.

Request
curl -X POST https://api.einvoicing.dev/v1/keys \  -H "Authorization: Bearer $EINVOICING_API_KEY" \  -H "Content-Type: application/json" \  -d '{ "name": "GitHub Actions", "mode": "test", "expires_at": "2027-09-11T00:00:00.000Z" }'

Request body

application/json· required

FieldTypeDescription
namerequiredstringWhat the key is for, so it can be recognised later. It is not secret.
modestringlive keys are metered and can manage the account; test keys are free and cannot.

livetest

expires_atstring or null · date-timeWhen the key stops working. Null means it never expires. Short expiries suit CI.
Example bodyapplication/json
{  "name": "GitHub Actions",  "mode": "test",  "expires_at": "2027-09-11T00:00:00.000Z"}

Response

201

The key was created. Store secret now.

FieldTypeDescription
datarequiredNewApiKeyA key as created, the only time its secret is ever shown. The fields of ApiKey plus secret. It is spelled out in full rather than composed with allOf, because ApiKey refuses unknown fields and would reject secret.
Example responseapplication/json
{  "data": {    "id": "01J9Z4C2E4G6J8M0N2Q4S6V8W0",    "name": "GitHub Actions",    "mode": "test",    "prefix": "einv_test_p7r2c8vn",    "created_at": "2026-09-11T16:00:00.000Z",    "last_used_at": null,    "expires_at": "2027-09-11T00:00:00.000Z",    "revoked_at": null,    "secret": "einv_test_p7r2c8vn_Hq3Lm9Xw2Ks7Pd4Vz8Nb1Tc6Rf0Jy5Ga3Ue7Wo"  }}

Errors

Every error is application/problem+json (RFC 9457). Branch on type, which is stable, never on title or detail.

StatusWhen
400

The body could not be parsed as the XML or JSON its Content-Type declares. Distinct from 422, which means the body parsed and its contents were rejected. Problem type is malformed-body.

/problems/malformed-body

401

No key, or a key that is unknown or revoked. Problem type is unauthenticated.

/problems/unauthenticated

403

A test key cannot manage keys or billing. Use a live key. Problem type is live-key-required.

422

The body parsed and was rejected. Includes unknown fields, which are refused rather than silently dropped. Problem type is invalid-request.

429

Too many requests in a short window. Slow down and retry after the number of seconds in Retry-After. Problem type is rate-limited.

/problems/rate-limited

Schemas

KeyRequest

How to set up a new key.

FieldTypeDescription
namerequiredstringWhat the key is for, so it can be recognised later. It is not secret.
modestringlive keys are metered and can manage the account; test keys are free and cannot.

livetest

expires_atstring or null · date-timeWhen the key stops working. Null means it never expires. Short expiries suit CI.

NewApiKey

A key as created, the only time its secret is ever shown. The fields of `ApiKey` plus `secret`. It is spelled out in full rather than composed with `allOf`, because `ApiKey` refuses unknown fields and would reject `secret`.

FieldTypeDescription
idrequiredUlidA ULID. Opaque and time-ordered.
namerequiredstringWhat the key is for.
moderequiredstringWhether the key is metered (live) or free and limited (test).

livetest

prefixrequiredstringThe public start of the key, enough to recognise it and never enough to use it.
created_atrequiredTimestamp · date-timeRFC 3339, UTC, millisecond precision.
last_used_atrequiredstring or null · date-timeAlways null on a key that was just created.
expires_atrequiredstring or null · date-timeWhen the key stops working. Null if never.
revoked_atrequiredstring or null · date-timeAlways null on a key that was just created.
secretrequiredstringThe full key. Store it now. It cannot be retrieved again.