Appearance
Management API
Manage users and groups from your own scripts and tools: onboard new starters, sync teams, or disable someone when they leave. To provision from Okta or Entra ID, use SCIM instead.
The API is at your organization's URL. The console also shows it on Settings > API keys:
https://acme.fobauth.com/v1Requests and responses are JSON.
API keys
Every request needs an API key, sent as a bearer token:
sh
curl https://acme.fobauth.com/v1/users \
-H "Authorization: Bearer fob_sk_..."To create a key, open Settings > API keys and choose Create key. Give it a name, such as Billing service, the scopes it needs, and when it expires: 30 days, 90 days, 1 year or never.
Permission
Creating and revoking keys needs Manage API keys and webhooks. You can only give a key scopes your own role covers. See Admins and roles.
Warning
Fob shows the key only once. Copy it into your secrets store straight away.
A key works only for its own organization. Revoked and expired keys stop working immediately. Changes made with a key appear in the audit log under the key's name.
Scopes
| Scope | Allows |
|---|---|
users:read | Read users |
users:write | Create, change and delete users |
groups:read | Read groups |
groups:write | Create and delete groups, and change their members |
applications:read | Read apps |
scim | Provision users and groups with SCIM |
Write scopes don't include read. A key that creates users and reads them back needs both users:write and users:read.
Endpoints
| Method | Path | Scope | Does |
|---|---|---|---|
GET | /v1/users | users:read | List users |
POST | /v1/users | users:write | Create a user |
GET | /v1/users/{user} | users:read | Get a user |
PATCH | /v1/users/{user} | users:write | Update a user |
DELETE | /v1/users/{user} | users:write | Delete a user. Returns 204. |
GET | /v1/groups | groups:read | List groups |
POST | /v1/groups | groups:write | Create a group |
GET | /v1/groups/{group} | groups:read | Get a group and its members |
DELETE | /v1/groups/{group} | groups:write | Delete a group. Returns 204. |
PUT | /v1/groups/{group}/members/{user} | groups:write | Add a user to a group. Returns 204. |
DELETE | /v1/groups/{group}/members/{user} | groups:write | Remove a user from a group. Returns 204. |
GET | /v1/applications | applications:read | List apps |
{user} and {group} are Fob IDs (UUIDs).
Users
List users
GET /v1/users returns users, newest first, one page at a time.
| Query parameter | Meaning |
|---|---|
search | Part of an email or name |
status | active, invited, unverified or disabled |
limit | Users per page. Default 50, maximum 200. |
after | The next value from the previous page |
json
{
"data": [
{
"id": "0193f3c4-a1b2-7c7e-9d0e-5b3f8a6c2d41",
"email": "ada@acme.com",
"name": "Ada Lovelace",
"status": "active",
"created_at": "2026-10-02T09:14:00Z",
"last_sign_in_at": "2026-11-08T17:40:21Z"
}
],
"next": "AAAAAAAAAAAYdGk0c2pXAAGT88ShsnyenQ5bP4psLUE"
}| Status | Meaning |
|---|---|
active | Can sign in |
invited | Hasn't accepted their invitation yet. Users from SCIM or an identity provider are never invited. |
unverified | Hasn't confirmed their email address, so can't sign in yet |
disabled | Can't sign in |
Get a user
GET /v1/users/{user} returns the user with their custom attributes and groups:
json
{
"id": "0193f3c4-a1b2-7c7e-9d0e-5b3f8a6c2d41",
"email": "ada@acme.com",
"name": "Ada Lovelace",
"status": "active",
"has_password": true,
"email_verified_at": "2026-10-02T09:15:12Z",
"disabled_at": null,
"created_at": "2026-10-02T09:14:00Z",
"last_sign_in_at": "2026-11-08T17:40:21Z",
"locked_until": null,
"attributes": { "employee_id": "E1042" },
"groups": [{ "id": "0193e8a0-55c1-7d2a-b6f4-1c9e0a7d3b58", "name": "Platform" }]
}locked_until is set while the account is locked after too many wrong passwords.
Create a user
sh
curl https://acme.fobauth.com/v1/users \
-H "Authorization: Bearer fob_sk_..." \
-H "Content-Type: application/json" \
-d '{
"email": "grace@acme.com",
"name": "Grace Hopper",
"attributes": { "employee_id": "E1043" }
}'| Field | Required | Meaning |
|---|---|---|
email | Yes | The user's email |
name | No | Display name |
password | No | Sets a password, so the account is ready to use and its email counts as confirmed. It must meet your password policy. Leave it out and Fob emails the user an invitation instead. |
attributes | No | Custom attribute values |
Returns 201 Created with the user, in the same shape as Get a user. If any attribute is invalid, nothing is created and no email is sent.
Invitation emails count towards the email limits.
Update a user
PATCH /v1/users/{user} changes only the fields you send. All changes apply together, or none do.
| Field | Meaning |
|---|---|
name | New display name. null clears it. |
email | New email. The user is signed out and must confirm the new address, so Fob emails it a confirmation link, or an invitation if the user has no password. |
disabled | true disables the account and signs the user out. false enables it again. |
attributes | Attribute values to change. null clears one. |
sh
curl -X PATCH https://acme.fobauth.com/v1/users/0193f3c4-a1b2-7c7e-9d0e-5b3f8a6c2d41 \
-H "Authorization: Bearer fob_sk_..." \
-H "Content-Type: application/json" \
-d '{ "disabled": true }'Returns the updated user.
Groups
POST /v1/groups takes a name and an optional description, and returns 201 Created with the group. Names are 1 to 100 letters, digits, spaces, hyphens, underscores, dots or colons.
json
{
"id": "0193e8a0-55c1-7d2a-b6f4-1c9e0a7d3b58",
"name": "Platform",
"description": "Infrastructure and deploys",
"members": 12,
"built_in": null,
"created_at": "2026-09-30T11:02:45Z"
}members is the number of members. built_in is "everyone" for the built-in Everyone group, and null otherwise.
GET /v1/groups/{group} adds members_list, in the order members were added, one page at a time: 50 by default, up to 200 with limit. Pass members_next as after to get the next page. Each member has user_id, plus email, name and added_at if the key also has users:read.
Adding a user who's already a member succeeds. The Everyone group always holds every user, so its members_list is empty, and deleting it or changing its members returns 422 invalid.
Apps
GET /v1/applications lists your apps. Client secrets are never returned.
| Field | Meaning |
|---|---|
id, name, client_id, created_at | |
project_id | Your organization's ID |
kind | web, spa (browser app), native (desktop or mobile app) or saml |
redirect_uris, post_logout_redirect_uris | The app's redirect and sign-out URLs |
access | everyone or assigned. See Assignments. |
launch_url, show_in_apps | The app's tile on the apps page |
device_grant | Whether device sign-in is on |
email_domain | The domain of the email address sent to the app, or null for the primary address |
require_pkce | Whether sign-ins must use PKCE |
Paging
Lists that can grow long return a next value with each page. To get the following page, send it back as after, with the same search and status. On the last page, next is null.
sh
curl "https://acme.fobauth.com/v1/users?limit=200&after=AAAAAAAAAAAYdGk0c2pXAAGT88ShsnyenQ5bP4psLUE" \
-H "Authorization: Bearer fob_sk_..."Treat next as opaque. A value Fob didn't give you returns 422 invalid. Users created while you're paging won't appear in that run, and no user appears twice.
Errors
Errors have a code and a message you can show to people:
json
{ "error": "insufficient_scope", "message": "This API key doesn't have the users:write scope." }| Status | error | When |
|---|---|---|
| 401 | unauthorized | The key is missing, wrong, revoked, expired or from another organization |
| 403 | insufficient_scope | The key doesn't have the scope the endpoint needs. The message names it. |
| 404 | not_found | No such user, group or path |
| 409 | taken | The email or name is already in use |
| 422 | invalid | A value failed validation. The message says which. |
| 429 | rate_limited | Too many requests or emails. Wait the number of seconds in Retry-After. See Rate limits. |
| 500 | internal | Something failed on Fob's side |
| 503 | busy | Fob is briefly overloaded. Wait the number of seconds in Retry-After. |