Skip to content

Authentication

Create an account, sign in and manage the session.

Exchange an email and password for a session. The response carries the access token; the refresh token is set as an httpOnly cookie. An unverified account gets 403 EMAIL_NOT_VERIFIED. Failed attempts are rate limited (5 per 15 minutes per IP and email).

Auth: None

Request body

{
"email": "owner@example.com",
"password": "a-long-passphrase"
}

Response

{
"data": {
"accessToken": "eyJhbGciOi…",
"expiresAt": "2026-10-04T18:30:00.000Z"
},
"meta": {
"requestId": "…"
}
}

End the session. Returns 204. The access token is deny-listed immediately.

Auth: None

Rotate the session using the graft_refresh cookie. The old refresh token stops working. Presenting an already-used token revokes the whole token family.

Auth: None

Send a fresh verification link to an unverified account. Always answers the same way, so it can’t be used to discover which emails have accounts.

Auth: None

Request body

{
"email": "owner@example.com"
}

Create an account and a workspace. Sends a verification email, and the account can’t sign in until the address is verified. New workspaces start a 14-day Premium trial with no card. Pass inviteToken instead of businessName to join an existing workspace.

Auth: None

Request body

{
"email": "owner@example.com",
"password": "a-long-passphrase",
"businessName": "Bella's Barbershop"
}

Mint a token for another workspace you belong to. One token is always one workspace.

Auth: Bearer token

Request body

{
"tenantId": "000000000000000000000001"
}

Spend the token from the verification email.

Auth: None

Request body

{
"token": "…"
}