Skip to content

Open a workspace

POST
/v1/workspaces
curl --request POST \
--url https://api.facteur.eu/v1/workspaces \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "name": "example", "tag": "example", "color": "example" }'

The slug is derived from the name and made unique within the organization; it is what every other route addresses the workspace by.

A workspace created by a key does not enter that key’s scope, and no member row is written for it — a key is not a person, and attributing the act to the human who minted the key is the one thing a trace must not do.

Media typeapplication/json
object
name
required
string
tag
string | null
color

One of eight names, so no free value reaches the stylesheet.

string | null
Examplegenerated
{
"name": "example",
"tag": "example",
"color": "example"
}

The workspace.

Media typeapplication/json
object
slug
required

How every other route addresses this workspace. The internal id never leaves.

string
name
required
string
createdAt
required
string format: date-time
isDefault
required

The workspace every member of the organization reaches without being added to it.

boolean
tag
string | null
color
string | null
inboxCount
integer
memberCount

Null on the default workspace, which has no member rows because everyone is in it.

integer | null
messagesThisMonth
integer
canManage
boolean
quota

The ceilings in force. monthly.messages always carries the figure being enforced, whether the customer wrote a number or a share of the plan, so an interface renders it without knowing which. percent is present only when a share is how it was written.

object
daily

Messages accepted per day, or null for no daily ceiling.

integer | null
monthly
object
messages

The ceiling being enforced. Null next to a percent means the plan sells no monthly envelope for that share to apply to, so the rule holds nothing back — shown rather than hidden.

integer | null
percent

Present only when the ceiling was written as a share of the plan.

integer
onExceed

What happens to mail past the ceiling.

string
Examplegenerated
{
"slug": "example",
"name": "example",
"createdAt": "2026-04-15T12:00:00Z",
"isDefault": true,
"tag": "example",
"color": "example",
"inboxCount": 1,
"memberCount": 1,
"messagesThisMonth": 1,
"canManage": true,
"quota": {
"daily": 1,
"monthly": {
"messages": 1,
"percent": 1
},
"onExceed": "example"
}
}

NAME_REQUIRED, NAME_TOO_LONG, NAME_NOT_SLUGGABLE (nothing in the name survives as a URL), TAG_INVALID, COLOR_INVALID, or INVALID_JSON.

Media typeapplication/json

Every failure has this shape. Branch on error.code; error.message is written for a human and is in French today.

object
error
required
object
code
required

The stable, machine-readable reason.

string
message

A sentence for whoever is reading the failure. Not part of the contract.

string
Example
{
"error": {
"code": "SCOPE_INSUFFICIENT"
}
}

No usable credential. UNAUTHENTICATED when none was presented, KEY_UNKNOWN, KEY_REVOKED or KEY_EXPIRED when a key was — kept distinct on purpose, because “mint a new one” and “somebody took this away from you” are different facts to whoever is reading a red pipeline.

Media typeapplication/json

Every failure has this shape. Branch on error.code; error.message is written for a human and is in French today.

object
error
required
object
code
required

The stable, machine-readable reason.

string
message

A sentence for whoever is reading the failure. Not part of the contract.

string
Example
{
"error": {
"code": "SCOPE_INSUFFICIENT"
}
}

WORKSPACE_LIMIT_REACHED — the plan includes fewer workspaces than this would make.

Media typeapplication/json

A refusal that a different plan would not produce. Carries what to change.

object
error
required
object
code
required
string
message
required
string
currentPlan
string
requiredPlan
string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"currentPlan": "example",
"requiredPlan": "example"
}
}

SCOPE_INSUFFICIENT (the message names the scope this request wanted and the ones the key holds), KEY_CANNOT_REACH (no scope opens this route to a key at all), FORBIDDEN, or one of the stated refusals listed under x-api-key-refusals.

Media typeapplication/json

Every failure has this shape. Branch on error.code; error.message is written for a human and is in French today.

object
error
required
object
code
required

The stable, machine-readable reason.

string
message

A sentence for whoever is reading the failure. Not part of the contract.

string
Example
{
"error": {
"code": "SCOPE_INSUFFICIENT"
}
}