Skip to content

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/v1

Requests 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 ​

ScopeAllows
users:readRead users
users:writeCreate, change and delete users
groups:readRead groups
groups:writeCreate and delete groups, and change their members
applications:readRead apps
scimProvision 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 ​

MethodPathScopeDoes
GET/v1/usersusers:readList users
POST/v1/usersusers:writeCreate a user
GET/v1/users/{user}users:readGet a user
PATCH/v1/users/{user}users:writeUpdate a user
DELETE/v1/users/{user}users:writeDelete a user. Returns 204.
GET/v1/groupsgroups:readList groups
POST/v1/groupsgroups:writeCreate a group
GET/v1/groups/{group}groups:readGet a group and its members
DELETE/v1/groups/{group}groups:writeDelete a group. Returns 204.
PUT/v1/groups/{group}/members/{user}groups:writeAdd a user to a group. Returns 204.
DELETE/v1/groups/{group}/members/{user}groups:writeRemove a user from a group. Returns 204.
GET/v1/applicationsapplications:readList apps

{user} and {group} are Fob IDs (UUIDs).

Users ​

List users ​

GET /v1/users returns users, newest first, one page at a time.

Query parameterMeaning
searchPart of an email or name
statusactive, invited, unverified or disabled
limitUsers per page. Default 50, maximum 200.
afterThe 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"
}
StatusMeaning
activeCan sign in
invitedHasn't accepted their invitation yet. Users from SCIM or an identity provider are never invited.
unverifiedHasn't confirmed their email address, so can't sign in yet
disabledCan'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" }
  }'
FieldRequiredMeaning
emailYesThe user's email
nameNoDisplay name
passwordNoSets 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.
attributesNoCustom 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.

FieldMeaning
nameNew display name. null clears it.
emailNew 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.
disabledtrue disables the account and signs the user out. false enables it again.
attributesAttribute 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.

FieldMeaning
id, name, client_id, created_at
project_idYour organization's ID
kindweb, spa (browser app), native (desktop or mobile app) or saml
redirect_uris, post_logout_redirect_urisThe app's redirect and sign-out URLs
accesseveryone or assigned. See Assignments.
launch_url, show_in_appsThe app's tile on the apps page
device_grantWhether device sign-in is on
email_domainThe domain of the email address sent to the app, or null for the primary address
require_pkceWhether 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." }
StatuserrorWhen
401unauthorizedThe key is missing, wrong, revoked, expired or from another organization
403insufficient_scopeThe key doesn't have the scope the endpoint needs. The message names it.
404not_foundNo such user, group or path
409takenThe email or name is already in use
422invalidA value failed validation. The message says which.
429rate_limitedToo many requests or emails. Wait the number of seconds in Retry-After. See Rate limits.
500internalSomething failed on Fob's side
503busyFob is briefly overloaded. Wait the number of seconds in Retry-After.