Oligon Receipts is in private beta — request access.
API reference
Authentication

Authentication

Email + password, magic link, and invitation flows for the dashboard. All endpoints below mint or consume JWT session tokens (Authorization: Bearer <jwt>) and also set oligon_access / oligon_refresh HttpOnly cookies. For machine-to-machine API key auth see API keys.

MethodPathAuth
POST/v1/auth/signuppublic
POST/v1/auth/loginpublic
POST/v1/auth/refreshrefresh token (cookie or body)
POST/v1/auth/logoutpublic
GET/v1/auth/meJWT
POST/v1/auth/magic-linkpublic
POST/v1/auth/magic-link/verifyone-shot link token
POST/v1/auth/accept-inviteone-shot invite token
POST/v1/auth/verify-email/{token}one-shot link token

POST /v1/auth/signup

Creates a User, an Org (owner = the new user), a free plan Subscription, and sends a verify-email link. Returns a session.

Request body

FieldTypeRequiredNotes
emailstringyesMust not be a disposable domain.
passwordstringyes8–128 chars.
full_namestringno≤255 chars.
org_namestringyes1–255 chars. Slug derived from it.
curl https://api.receipts.oligontech.com/v1/auth/signup \
  -H "Content-Type: application/json" \
  -d '{"email":"ana@example.com","password":"correct-horse","org_name":"Ana Inc"}'

Response — 201 Created

{
  "access_token":  "eyJhbGc...",
  "refresh_token": "eyJhbGc...",
  "token_type":    "Bearer",
  "expires_in":    900,
  "user_id":       "01HQX...",
  "org_id":        "01HQX..."
}

Errors

StatusCodeCause
400validation_errorDisposable email domain.
409conflictEmail already registered.
429rate_limit_exceededToo many signups from this IP in 1 h.

POST /v1/auth/login

curl https://api.receipts.oligontech.com/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"ana@example.com","password":"correct-horse"}'

Returns the same TokenResponse as signup with status 200.

StatusCodeCause
401authentication_failedBad credentials or disabled account.

If the user has 2FA enabled, complete login by posting the code to /v1/auth/2fa/verify.

POST /v1/auth/refresh

Reads the refresh token from either the oligon_refresh cookie or a JSON body { "refresh_token": "..." }, then issues a new access + refresh pair (refresh is rotated).

curl https://api.receipts.oligontech.com/v1/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{"refresh_token":"eyJhbGc..."}'

Returns TokenResponse with status 200. 401 authentication_failed if the token is missing, malformed, expired, or of the wrong type.

POST /v1/auth/logout

Clears the oligon_access and oligon_refresh cookies. Public — does not require auth, does not invalidate the JWT on the server (JWTs are stateless).

{ "ok": true }

GET /v1/auth/me

Returns the active user + org for the portal frontend.

curl https://api.receipts.oligontech.com/v1/auth/me \
  -H "Authorization: Bearer $JWT"
{
  "user": {
    "id": "01HQX...",
    "email": "ana@example.com",
    "name": null,
    "created_at": "2026-06-01T00:00:00+00:00"
  },
  "org": {
    "id": "01HQX...",
    "name": "Ana Inc",
    "slug": "ana-inc",
    "plan": "free",
    "billing_email": "ana@example.com"
  },
  "role": "owner"
}

org and role are null if the user has no membership yet.

POST /v1/auth/magic-link

Send a one-shot sign-in link to the email. Always returns 202 with {"ok": true} whether or not the address exists (no enumeration).

curl https://api.receipts.oligontech.com/v1/auth/magic-link \
  -H "Content-Type: application/json" \
  -d '{"email":"ana@example.com"}'

POST /v1/auth/magic-link/verify

Exchange the token from the email link for a session.

curl https://api.receipts.oligontech.com/v1/auth/magic-link/verify \
  -H "Content-Type: application/json" \
  -d '{"token":"<from email>"}'

Returns TokenResponse. 400 validation_error if the token is unknown, expired, or already consumed (one-shot).

POST /v1/auth/accept-invite

Same body as magic-link verify ({ "token": "..." }). Looks up the Invitation, creates the user if they don't exist yet, adds a Membership with the role baked into the invite, and returns a session scoped to that org.

StatusCodeCause
400validation_errorInvite unknown, expired, revoked, or already accepted.

POST /v1/auth/verify-email/{token}

Confirms a verify-email link. One-shot: the token is deleted on the first redemption. Subsequent requests with the same (already-deleted) token return 400 validation_error.

curl -X POST https://api.receipts.oligontech.com/v1/auth/verify-email/<token>
{ "ok": true, "email": "ana@example.com", "verified": true }