Stitchflow
Cloudflare logo

Cloudflare User Management API Guide

API workflow

How to automate user lifecycle operations through APIs with caveats that matter in production.

UpdatedMar 16, 2026

Summary and recommendation

Cloudflare's member management API operates under two separate models that do not overlap.

The core REST API (`/accounts/{account_id}/members`) manages dashboard membership - who can log in and administer zones.

SCIM 2.0, available only on Cloudflare One Enterprise, manages Zero Trust user provisioning and session lifecycle.

Building an identity graph across both surfaces requires integrating both independently;

there is no unified endpoint that returns a complete picture of a user's access across dashboard roles and Zero Trust policies.

Authentication uses scoped API Tokens (Bearer) as the recommended method.

Legacy API Key + Email header authentication grants full user-level access without scope restrictions and is not recommended for new integrations.

Tokens are shown only once at creation;

store them immediately.

Rate limits apply globally at 1,200 requests per 5-minute rolling window per token across all endpoints.

No `Retry-After` header is documented in the API reference, so implement exponential backoff on HTTP 429 responses.

Pagination is offset-based with a maximum of 50 records per page (`page` / `per_page` params).

API quick reference

Has user APIYes
Auth methodAPI Token (Bearer) or API Key + Email header
Base URLOfficial docs
SCIM availableYes
SCIM plan requiredEnterprise (Cloudflare One / Zero Trust Enterprise)

Authentication

Auth method: API Token (Bearer) or API Key + Email header

Setup steps

  1. Log in to the Cloudflare dashboard at dash.cloudflare.com.
  2. Navigate to My Profile > API Tokens.
  3. Click 'Create Token' and select a template or build a custom token.
  4. Assign required permission scopes (e.g., Account > Members: Edit).
  5. Optionally restrict token by IP range and set an expiry.
  6. Copy the generated token; it is shown only once.
  7. Use the token as a Bearer token: Authorization: Bearer . Alternatively, use legacy API Key with X-Auth-Key and X-Auth-Email headers (not recommended for new integrations).

Required scopes

Scope Description Required for
Account > Members: Read Read account member list and individual member details. GET /accounts/{account_id}/members
Account > Members: Edit Add, update, and remove account members and their roles. POST/PUT/DELETE /accounts/{account_id}/members
Account > Roles: Read List available roles that can be assigned to members. GET /accounts/{account_id}/roles
User > User Details: Read Read the authenticated user's own profile. GET /user
User > User Details: Edit Update the authenticated user's own profile. PATCH /user

User object / data model

Field Type Description On create On update Notes
id string (UUID) Unique identifier for the account member. system-assigned immutable Used as path parameter for member-specific operations.
user.id string (UUID) Cloudflare user ID of the member. system-assigned immutable Distinct from the membership ID.
user.email string Email address of the member. required not updatable via member API Used to invite a new member.
user.first_name string First name of the user. optional read-only via member API Set by the user on their own profile.
user.last_name string Last name of the user. optional read-only via member API Set by the user on their own profile.
user.two_factor_authentication_enabled boolean Whether the user has 2FA enabled. read-only read-only Informational only; cannot be set via API.
roles array of role objects List of roles assigned to the member within the account. required (at least one role ID) replaceable via PUT Role IDs must be retrieved from GET /accounts/{id}/roles.
status string (enum) Membership status: 'accepted', 'pending', 'rejected'. system-assigned ('pending' until invite accepted) read-only New invites start as 'pending'.
policies array Fine-grained access policies (newer accounts may use policies instead of roles). optional replaceable via PUT Policies provide more granular permission control than roles.

Core endpoints

List Account Members

  • Method: GET
  • URL: https://api.cloudflare.com/client/v4/accounts/{account_id}/members
  • Watch out for: Returns only members of the specified account. Pagination uses page/per_page; max per_page is 50.

Request example

GET /client/v4/accounts/abc123/members?page=1&per_page=20
Authorization: Bearer <token>

Response example

{
  "result": [{"id":"mem1","user":{"email":"user@example.com"},"roles":[{"id":"role1","name":"Administrator"}],"status":"accepted"}],
  "result_info": {"page":1,"per_page":20,"total_count":1}
}

Get Account Member

  • Method: GET
  • URL: https://api.cloudflare.com/client/v4/accounts/{account_id}/members/{member_id}
  • Watch out for: member_id is the membership UUID, not the user UUID.

Request example

GET /client/v4/accounts/abc123/members/mem1
Authorization: Bearer <token>

Response example

{
  "result": {"id":"mem1","user":{"email":"user@example.com","first_name":"Jane"},"roles":[{"id":"role1","name":"Administrator"}],"status":"accepted"}
}

Add Account Member (Invite)

  • Method: POST
  • URL: https://api.cloudflare.com/client/v4/accounts/{account_id}/members
  • Watch out for: Invited user receives an email and must accept. Status remains 'pending' until accepted. Role IDs must be valid for the account.

Request example

POST /client/v4/accounts/abc123/members
Content-Type: application/json

{"email":"newuser@example.com","roles":["role-id-here"]}

Response example

{
  "result": {"id":"mem2","user":{"email":"newuser@example.com"},"roles":[{"id":"role-id-here"}],"status":"pending"}
}

Update Account Member Roles

  • Method: PUT
  • URL: https://api.cloudflare.com/client/v4/accounts/{account_id}/members/{member_id}
  • Watch out for: PUT replaces the entire roles array. Omitting a role removes it. Use GET first to preserve existing roles if needed.

Request example

PUT /client/v4/accounts/abc123/members/mem1
Content-Type: application/json

{"roles":[{"id":"new-role-id"}]}

Response example

{
  "result": {"id":"mem1","roles":[{"id":"new-role-id","name":"Billing"}],"status":"accepted"}
}

Remove Account Member

  • Method: DELETE
  • URL: https://api.cloudflare.com/client/v4/accounts/{account_id}/members/{member_id}
  • Watch out for: Removes the member from the account immediately. Does not delete the underlying Cloudflare user account.

Request example

DELETE /client/v4/accounts/abc123/members/mem1
Authorization: Bearer <token>

Response example

{
  "result": {"id":"mem1"}
}

List Account Roles

  • Method: GET
  • URL: https://api.cloudflare.com/client/v4/accounts/{account_id}/roles
  • Watch out for: Role IDs are account-specific. Always fetch roles for the target account before assigning.

Request example

GET /client/v4/accounts/abc123/roles
Authorization: Bearer <token>

Response example

{
  "result": [{"id":"role1","name":"Administrator","description":"Full account access","permissions":{}}]
}

Get Current User (Self)

  • Method: GET
  • URL: https://api.cloudflare.com/client/v4/user
  • Watch out for: Returns the profile of the token owner only. Cannot retrieve arbitrary users by ID via this endpoint.

Request example

GET /client/v4/user
Authorization: Bearer <token>

Response example

{
  "result": {"id":"user-uuid","email":"me@example.com","first_name":"Jane","last_name":"Doe","two_factor_authentication_enabled":true}
}

Update Current User (Self)

  • Method: PATCH
  • URL: https://api.cloudflare.com/client/v4/user
  • Watch out for: Only the authenticated user can update their own profile. Admins cannot update other users' profiles via this endpoint.

Request example

PATCH /client/v4/user
Content-Type: application/json

{"first_name":"Jane","last_name":"Smith"}

Response example

{
  "result": {"id":"user-uuid","email":"me@example.com","first_name":"Jane","last_name":"Smith"}
}

Rate limits, pagination, and events

  • Rate limits: Cloudflare enforces a global rate limit of 1,200 requests per 5-minute rolling window per API token. Exceeding this returns HTTP 429.
  • Rate-limit headers: Yes
  • Retry-After header: No
  • Rate-limit notes: The API returns HTTP 429 when the limit is exceeded. Official docs note the 1,200/5-min limit but do not document specific rate-limit response headers or a Retry-After header in the API reference.
  • Pagination method: offset
  • Default page size: 20
  • Max page size: 50
  • Pagination pointer: page / per_page
Plan Limit Concurrent
All plans 1,200 requests per 5 minutes per token 0
  • Webhooks available: No
  • Webhook notes: Cloudflare does not offer native webhooks for user/member management events via the core API. Cloudflare Notifications (for zone/account events like DDoS, health checks) exist but do not cover user provisioning or membership changes.
  • Alternative event strategy: Use Cloudflare Audit Logs API (GET /accounts/{id}/audit_logs) to poll for membership change events. For real-time provisioning, use SCIM with a supported IdP.

SCIM API status

  • SCIM available: Yes

  • SCIM version: 2.0

  • Plan required: Enterprise (Cloudflare One / Zero Trust Enterprise)

  • Endpoint: Tenant-specific endpoint generated during IdP SCIM configuration in the Cloudflare Zero Trust dashboard (Settings > Authentication > Login methods > SCIM). The endpoint URL is unique per IdP connector and is not a static public URL.

  • Supported operations: Create user (POST /Users), Read user (GET /Users/{id}), List users (GET /Users), Update user (PATCH /Users/{id}), Deactivate/deprovision user (PATCH /Users/{id} with active:false), Create group (POST /Groups), Read group (GET /Groups/{id}), List groups (GET /Groups), Update group membership (PATCH /Groups/{id}), Delete group (DELETE /Groups/{id})

Limitations:

  • Requires Enterprise plan for Cloudflare One (Zero Trust).
  • SSO must be configured before SCIM can be enabled.
  • Officially supported IdPs: Okta and Microsoft Entra ID (Azure AD). Other IdPs may work but are not officially documented.
  • SCIM endpoint URL is dynamically generated per IdP setup; there is no static tenant-independent base URL.
  • SCIM provisions users into Cloudflare Access/Zero Trust, not into the core Cloudflare dashboard account membership.
  • Deprovisioning sets user to inactive in Access but does not delete the Cloudflare account.
  • Groups synced via SCIM can be used in Access policies but group management is IdP-driven.

Common scenarios

Three scenarios cover the majority of programmatic use cases:

Invite a new member: Fetch role IDs first via GET /accounts/{account_id}/roles - role IDs are account-specific and must not be hardcoded.

POST /accounts/{account_id}/members with the target email and role ID array.

The returned status will be pending until the user accepts the invitation email;

poll GET /accounts/{account_id}/members/{member_id} to confirm accepted.

Remove a departing employee: Locate the member_id (membership UUID, distinct from user UUID) by filtering GET /accounts/{account_id}/members by user.email.

Issue DELETE /accounts/{account_id}/members/{member_id}.

This removes dashboard access only.

If the user has Cloudflare One access, their IdP account must be deprovisioned separately - or via SCIM if configured - to revoke application-level sessions.

API tokens belonging to the removed user remain valid until explicitly deleted from their personal profile.

SCIM provisioning with Okta (Enterprise): The SCIM base URL is dynamically generated per IdP connector in the Zero Trust dashboard (Settings > Authentication > Login methods).

It is not a static public URL and rotates if regenerated.

Configure Okta with the generated URL and Bearer token, enable Push Users and Push Groups, then assign users to the Cloudflare app.

Deactivation in Okta sends PATCH /Users/{id} with active:false, revoking Access sessions.

This does not remove the user as a core dashboard account member - that requires a separate DELETE /accounts/{id}/members call.

Invite a new team member with a specific role

  1. GET /accounts/{account_id}/roles to retrieve available role IDs for the account.
  2. Identify the desired role ID (e.g., 'Administrator Read Only').
  3. POST /accounts/{account_id}/members with body {"email": "newuser@example.com", "roles": [""]}.
  4. Capture the returned membership ID and status ('pending').
  5. Notify the user to accept the invitation email from Cloudflare.
  6. Poll GET /accounts/{account_id}/members/{member_id} until status changes to 'accepted'.

Watch out for: The invitation email is sent by Cloudflare automatically. If the user already has a Cloudflare account, they accept via the dashboard. If not, they must create one first.

Remove a departing employee from the account

  1. GET /accounts/{account_id}/members?page=1&per_page=50 and filter by user.email to find the member_id.
  2. DELETE /accounts/{account_id}/members/{member_id}.
  3. Verify removal with GET /accounts/{account_id}/members and confirm the member no longer appears.

Watch out for: This removes dashboard access only. If the user also has Cloudflare One/Zero Trust access, their IdP account must be deprovisioned separately (or via SCIM if configured) to revoke application-level access.

Provision and deprovision users via SCIM with Okta (Enterprise)

  1. Ensure Cloudflare One Enterprise plan is active and SSO is configured with Okta as the identity provider.
  2. In Cloudflare Zero Trust dashboard: Settings > Authentication > Login methods, enable SCIM for the Okta connector.
  3. Copy the generated SCIM base URL and Bearer token from the Cloudflare dashboard.
  4. In Okta, configure the Cloudflare app's provisioning settings with the SCIM URL and token.
  5. Enable 'Push Users' and 'Push Groups' in Okta provisioning settings.
  6. Assign users/groups to the Cloudflare app in Okta; Okta will POST to the SCIM /Users endpoint.
  7. To deprovision, deactivate or unassign the user in Okta; Okta sends PATCH /Users/{id} with active:false, revoking Access sessions.

Watch out for: SCIM endpoint URL is unique per IdP configuration and rotates if regenerated. Deprovisioning via SCIM revokes Zero Trust/Access sessions but does not remove the user as an account member in the core Cloudflare dashboard - that requires a separate DELETE /accounts/{id}/members call.

Why building this yourself is a trap

The most consequential API caveat is the split between dashboard membership and Zero Trust identity. An identity graph built solely on /accounts/{account_id}/members will be incomplete for any organization using Cloudflare One - Zero Trust users who authenticate via Access are tracked in a separate user store and are not returned by the members endpoint.

Accurate identity coverage requires querying both surfaces and reconciling on user.email as the common key.

PUT /accounts/{account_id}/members/{member_id} replaces the entire roles array on every call. Omitting a role silently removes it. Always GET the current member record first and merge roles before issuing a PUT.

The /user endpoint returns only the token owner's profile. There is no admin endpoint to retrieve arbitrary user profiles by user ID - user details are only accessible in the context of account membership records.

This limits the API's utility for user lookup outside of a known account scope and is a structural constraint to account for when designing any identity graph or directory sync.

Automate Cloudflare workflows without one-off scripts

Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.

Every app coverage, including apps without APIs
60+ app integrations plus browser automation for apps without APIs
IT graph reconciliation across apps and your IdP
Less than a week to launch, maintained as APIs and admin consoles change
SOC 2 Type II. ~2 hours of your team's time

UpdatedMar 16, 2026

* Details sourced from official product documentation and admin references.

Keep exploring

Related apps

15Five logo

15Five

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

15Five uses a fixed role-based permission model with six predefined roles: Account Admin, HR Admin, Billing Admin, Group Admin, Manager, and Employee. No custom roles can be constructed. User management lives at Settings gear → People → Manage people p

1Password logo

1Password

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

1Password's admin console at my.1password.com covers the full user lifecycle — invitations, group assignments, vault access, suspension, and deletion — without any third-party tooling. Like every app that mixes role-based and resource-level permissions

8x8 logo

8x8

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

8x8 Admin Console supports full lifecycle user management — create, deactivate, and delete — across its X Series unified communications platform. Every app a user can access (8x8 Work desktop, mobile, web, Agent Workspace) is gated by license assignmen