Summary and recommendation
Webflow exposes two distinct, non-overlapping user management surfaces: the Data API (`/v2/sites/{site_id}/users`) for site Membership end-users, and the SCIM 2.0 API (`https://api.webflow.com/scim/v2`) for workspace collaborators. These use separate auth tokens and operate on separate identity records - conflating them is the most common integration error.
The Data API uses OAuth 2.0 (authorization code flow) or site-scoped API keys. Required scopes for full user lifecycle management are `users:read` and `users:write`. The SCIM API uses a long-lived bearer token generated in Workspace Settings > Security and is restricted to Enterprise Workspace plans with active SSO.
For teams building an identity graph across Webflow and other tools, the key join fields are `email` (present on both Data API user objects and SCIM records), `id` (Webflow-assigned, surface-specific), and `accessGroups` (site-level grouping for Data API users).
Note that workspace collaborator identity and site Membership identity are separate nodes in any identity graph - a single human may have records in both systems with no shared Webflow-native identifier linking them.
API quick reference
| Has user API | Yes |
| Auth method | OAuth 2.0 (authorization code flow) or API key (site-scoped token for server-side use) |
| Base URL | Official docs |
| SCIM available | Yes |
| SCIM plan required | Enterprise Workspace (annual billing required; SSO must be configured first) |
Authentication
Auth method: OAuth 2.0 (authorization code flow) or API key (site-scoped token for server-side use)
Setup steps
- Register an application in the Webflow App Dashboard (developers.webflow.com) to obtain a client_id and client_secret.
- Redirect users to https://webflow.com/oauth/authorize with response_type=code, client_id, redirect_uri, and space-separated scope values.
- Exchange the returned authorization code at https://api.webflow.com/oauth/access_token (POST) for an access_token.
- Include the token in all API requests as: Authorization: Bearer
. - For server-side automation without user context, generate a site API token in Webflow Site Settings > Integrations and use it as the Bearer token.
Required scopes
| Scope | Description | Required for |
|---|---|---|
| users:read | Read Membership user records for a site. | List Users, Get User |
| users:write | Create, update, and delete Membership user records. | Create/Invite User, Update User, Delete User |
| authorized_user:read | Read the profile of the authenticated Webflow account holder. | Get Authorized User (workspace-level identity) |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | string | Unique Webflow-assigned user ID. | system-generated | immutable | Used as path parameter in user-specific endpoints. |
| string | User's email address (login identifier). | required | not updatable via API | Must be unique within the site's membership. | |
| name | string | Display name of the user. | optional | updatable | |
| status | string (enum) | Membership status: invited, verified, unverified. | system-set | read-only | Reflects email verification state. |
| accessGroups | array of objects | List of access group slugs/IDs the user belongs to. | optional | updatable | Controls gated content access within Webflow Memberships. |
| data | object | Custom field data defined in the site's Member collection schema. | optional | updatable | Keys correspond to custom field slugs configured in Webflow Designer. |
| createdOn | string (ISO 8601) | Timestamp when the user record was created. | system-generated | immutable | |
| updatedOn | string (ISO 8601) | Timestamp of last update to the user record. | system-generated | system-updated | |
| lastLogin | string (ISO 8601) | Timestamp of the user's most recent login. | null | system-updated | |
| invitedOn | string (ISO 8601) | Timestamp when the invitation email was sent. | system-generated on invite | immutable |
Core endpoints
List Users
- Method: GET
- URL:
https://api.webflow.com/v2/sites/{site_id}/users - Watch out for: Only returns Membership (site-level) users, not Webflow workspace collaborators.
Request example
GET /v2/sites/abc123/users?limit=100&offset=0
Authorization: Bearer <token>
Response example
{
"users": [{"id":"u1","email":"a@b.com","name":"Alice","status":"verified"}],
"count": 1,
"limit": 100,
"offset": 0,
"total": 1
}
Get User
- Method: GET
- URL:
https://api.webflow.com/v2/sites/{site_id}/users/{user_id}
Request example
GET /v2/sites/abc123/users/u1
Authorization: Bearer <token>
Response example
{
"id": "u1",
"email": "a@b.com",
"name": "Alice",
"status": "verified",
"accessGroups": [{"slug":"premium"}],
"createdOn": "2024-01-10T12:00:00Z"
}
Invite User
- Method: POST
- URL:
https://api.webflow.com/v2/sites/{site_id}/users/invite - Watch out for: Triggers an invitation email to the user. Cannot create a user without sending an invite email via this endpoint.
Request example
POST /v2/sites/abc123/users/invite
Content-Type: application/json
{"email":"new@user.com","name":"Bob","accessGroups":["premium"]}
Response example
{
"id": "u2",
"email": "new@user.com",
"name": "Bob",
"status": "invited",
"invitedOn": "2025-06-01T09:00:00Z"
}
Update User
- Method: PATCH
- URL:
https://api.webflow.com/v2/sites/{site_id}/users/{user_id} - Watch out for: Email cannot be updated via the API. accessGroups replaces the full list; send all desired groups, not just additions.
Request example
PATCH /v2/sites/abc123/users/u1
Content-Type: application/json
{"name":"Alice Smith","accessGroups":["premium","vip"]}
Response example
{
"id": "u1",
"name": "Alice Smith",
"accessGroups": [{"slug":"premium"},{"slug":"vip"}],
"updatedOn": "2025-06-01T10:00:00Z"
}
Delete User
- Method: DELETE
- URL:
https://api.webflow.com/v2/sites/{site_id}/users/{user_id} - Watch out for: Permanently removes the user from site Membership. Cannot be undone via API.
Request example
DELETE /v2/sites/abc123/users/u1
Authorization: Bearer <token>
Response example
HTTP 200 OK
{}
Get Authorized User (workspace identity)
- Method: GET
- URL:
https://api.webflow.com/v2/token/authorized_by - Watch out for: Returns the Webflow workspace account that authorized the OAuth token, not a site Membership user.
Request example
GET /v2/token/authorized_by
Authorization: Bearer <token>
Response example
{
"id": "ws_user_abc",
"email": "admin@company.com",
"firstName": "Admin",
"lastName": "User"
}
List Access Groups
- Method: GET
- URL:
https://api.webflow.com/v2/sites/{site_id}/accessgroups - Watch out for: Access group slugs must be used (not IDs) when assigning groups during user invite or update.
Request example
GET /v2/sites/abc123/accessgroups
Authorization: Bearer <token>
Response example
{
"accessGroups": [{"id":"ag1","name":"Premium","slug":"premium"}],
"count": 1
}
List Sites (to resolve site_id)
- Method: GET
- URL:
https://api.webflow.com/v2/sites - Watch out for: site_id is required for all user endpoints; use this endpoint to discover it programmatically.
Request example
GET /v2/sites
Authorization: Bearer <token>
Response example
{
"sites": [{"id":"abc123","name":"My Site","shortName":"mysite"}]
}
Rate limits, pagination, and events
- Rate limits: Webflow enforces per-site, per-minute rate limits on the Data API. Limits vary by workspace plan.
- Rate-limit headers: Yes
- Retry-After header: Yes
- Rate-limit notes: Rate limit headers returned: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset. HTTP 429 is returned when exceeded. Retry-After header is included on 429 responses.
- Pagination method: offset
- Default page size: 100
- Max page size: 100
- Pagination pointer: limit / offset
| Plan | Limit | Concurrent |
|---|---|---|
| Starter / Basic | 60 requests/minute per site | 0 |
| Core / Growth | 120 requests/minute per site | 0 |
| Enterprise | 240 requests/minute per site (higher limits negotiable) | 0 |
- Webhooks available: Yes
- Webhook notes: Webflow supports webhooks for Membership events, allowing real-time notification of user lifecycle changes.
- Alternative event strategy: Poll GET /v2/sites/{site_id}/users with offset pagination if webhooks are not feasible.
- Webhook events: memberships_user_account_added, memberships_user_account_updated, memberships_user_account_deleted, memberships_user_session_login, memberships_user_session_logout
SCIM API status
SCIM available: Yes
SCIM version: 2.0
Plan required: Enterprise Workspace (annual billing required; SSO must be configured first)
Endpoint: https://api.webflow.com/scim/v2
Supported operations: GET /Users (list workspace members), GET /Users/{id} (get workspace member), POST /Users (provision workspace member), PATCH /Users/{id} (update workspace member attributes), DELETE /Users/{id} (deprovision workspace member), GET /Groups (list workspace teams/groups), PATCH /Groups/{id} (update group membership)
Limitations:
- SCIM manages Webflow workspace collaborator accounts, not site Membership (end-user) accounts.
- SSO (SAML 2.0) must be enabled before SCIM provisioning can be activated.
- Supported IdPs: Okta and Microsoft Entra ID (Azure AD). Google Workspace and OneLogin not officially supported.
- SCIM token is generated in Workspace Settings > Security; it is a long-lived bearer token, not OAuth.
- Group push support may be limited depending on IdP configuration.
Common scenarios
Three integration patterns cover the majority of production use cases:
Provision a site member and assign to an access group: Resolve site_id via GET /v2/sites, fetch group slugs via GET /v2/sites/{site_id}/accessgroups, then POST /v2/sites/{site_id}/users/invite with email, name, and accessGroups array. The invite email is always triggered - there is no silent creation path. Poll GET /v2/sites/{site_id}/users/{user_id} or subscribe to the memberships_user_account_updated webhook to confirm status transitions to verified.
Deprovision a workspace collaborator via SCIM (Okta): Requires Enterprise Workspace, active SSO, and SCIM configured in Workspace Settings > Security. Unassigning the user in Okta sends DELETE /scim/v2/Users/{id} to Webflow. This removes workspace access only - site Membership records are unaffected and must be deleted separately via DELETE /v2/sites/{site_id}/users/{user_id}.
Bulk access group sync: Paginate GET /v2/sites/{site_id}/users?limit=100&offset=0 through all users. For each target user, PATCH /v2/sites/{site_id}/users/{user_id} with the full accessGroups array. The PATCH is a full replacement - omitting a group removes it. Respect X-RateLimit-Remaining headers and implement exponential backoff on HTTP 429 responses.
Provision a new site member and assign to an access group
- GET /v2/sites to retrieve the target site_id.
- GET /v2/sites/{site_id}/accessgroups to retrieve available group slugs.
- POST /v2/sites/{site_id}/users/invite with {email, name, accessGroups:["slug"]} to invite the user.
- Poll GET /v2/sites/{site_id}/users/{user_id} or listen to memberships_user_account_updated webhook to confirm status changes to 'verified' after the user accepts the invite.
Watch out for: The invite email is always sent; there is no way to create a verified user without the user completing email verification.
Deprovision a workspace collaborator via SCIM (Okta)
- Ensure Enterprise Workspace plan, SSO, and SCIM are configured in Workspace Settings > Security.
- In Okta, unassign the user from the Webflow SCIM application.
- Okta sends DELETE /Users/{scim_user_id} to https://api.webflow.com/scim/v2/Users/{id}.
- Webflow removes the collaborator's workspace access; their site Membership accounts (if any) are unaffected.
Watch out for: SCIM deprovisioning only removes workspace access, not site Membership end-user accounts – those must be deleted separately via the Data API.
Sync access group changes for existing members in bulk
- GET /v2/sites/{site_id}/users?limit=100&offset=0 and paginate through all users.
- For each user requiring a group change, PATCH /v2/sites/{site_id}/users/{user_id} with the full desired accessGroups array.
- Respect rate limits (X-RateLimit-Remaining header); implement exponential backoff on HTTP 429.
- Optionally subscribe to memberships_user_account_updated webhook to confirm changes.
Watch out for: PATCH accessGroups replaces the entire group list; always include all groups the user should retain, not just the new ones.
Why building this yourself is a trap
Several API behaviors are non-obvious and will cause silent failures or data loss if not handled explicitly.
accessGroupsonPATCHis a full list replacement, not an additive merge. Sending only the new group removes all existing groups. Always read current state before writing.- Email cannot be updated via the Data API. Users must change it through the site's member portal. Any identity graph that uses email as a join key must account for this immutability on the API side.
- The invite endpoint always sends an email. There is no way to create a verified Membership user programmatically without user action on the invite.
- Rate limits are per-site, not per-token. Multiple integrations targeting the same site share the same limit bucket (60–240 req/min depending on plan). High-volume syncs on lower-tier plans will hit 429s.
- API v1 (
/v1) is deprecated. All new integrations must use/v2. - SCIM provisioning cannot be tested below Enterprise Workspace with active SSO. There is no sandbox or lower-tier equivalent.
- Site API tokens are single-site scoped; OAuth tokens can span multiple sites. Choose auth method based on whether your integration needs cross-site access.
Automate Webflow 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.