Summary and recommendation
Retool exposes a REST API at https://<your-retool-instance>/api/v1, authenticated via Bearer token generated under Settings → API → Access Tokens. Tokens are displayed only once at creation - store them immediately.
The API covers full user CRUD and group membership management, with scopes (users:read, users:write, groups:read, groups:write) controlling access. Rate limits are enforced but thresholds are not publicly documented; contact Retool support for enterprise-tier specifics.
Pagination uses offset-based page and pageSize params, defaulting to 100 records per page.
For teams building an identity graph across their SaaS stack, the userType field ('default' vs 'endUser') and the groups array on each user object are the two fields that carry the most structural weight - misclassifying userType has direct billing consequences.
API quick reference
| Has user API | Yes |
| Auth method | Bearer token (API Access Token) |
| Base URL | Official docs |
| SCIM available | Yes |
| SCIM plan required | Enterprise |
Authentication
Auth method: Bearer token (API Access Token)
Setup steps
- Log in to Retool as an admin.
- Navigate to Settings → API → Access Tokens.
- Click 'Create new token', assign a name and optional expiry.
- Copy the generated token; it is shown only once.
- Include the token in all API requests as: Authorization: Bearer
Required scopes
| Scope | Description | Required for |
|---|---|---|
| users:read | Read user profiles and list users | GET /users, GET /users/{id} |
| users:write | Create, update, and delete users | POST /users, PUT /users/{id}, DELETE /users/{id} |
| groups:read | Read group membership and group details | GET /groups, GET /groups/{id} |
| groups:write | Create, update, and delete groups | POST /groups, PUT /groups/{id}, DELETE /groups/{id} |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | string (UUID) | Unique Retool user identifier | auto-generated | immutable | Used as path param for user-specific operations |
| string | User's email address; used as login identifier | required | allowed | Must be unique within the organization | |
| firstName | string | User's first name | optional | allowed | |
| lastName | string | User's last name | optional | allowed | |
| profilePhotoUrl | string (URL) | URL of the user's profile photo | optional | allowed | |
| isAdmin | boolean | Whether the user has organization admin privileges | optional | allowed | Admins have full org access |
| isDisabled | boolean | Whether the user account is disabled | optional | allowed | Disabled users cannot log in |
| userType | string (enum) | Differentiates 'default' (standard) vs 'endUser' billing types | optional | allowed | Affects billing; end users are priced differently |
| groups | array of objects | Groups the user belongs to | optional | via group endpoints | Managed via /groups endpoints |
| createdAt | string (ISO 8601) | Timestamp of user creation | auto-generated | immutable | |
| updatedAt | string (ISO 8601) | Timestamp of last update | auto-generated | auto-updated |
Core endpoints
List users
- Method: GET
- URL:
/api/v1/users - Watch out for: Pagination is 1-indexed. Omitting pageSize defaults to 100 records.
Request example
GET /api/v1/users?page=1&pageSize=50
Authorization: Bearer <token>
Response example
{
"users": [
{"id": "uuid", "email": "user@example.com",
"firstName": "Jane", "isAdmin": false}
],
"total": 120
}
Get user by ID
- Method: GET
- URL:
/api/v1/users/{userId} - Watch out for: Returns 404 if user does not exist or belongs to a different org.
Request example
GET /api/v1/users/abc-123
Authorization: Bearer <token>
Response example
{
"id": "abc-123",
"email": "user@example.com",
"firstName": "Jane",
"isAdmin": false,
"isDisabled": false
}
Create user
- Method: POST
- URL:
/api/v1/users - Watch out for: Creating a user sends an invitation email. If SSO is enforced, the user must authenticate via SSO on first login.
Request example
POST /api/v1/users
Authorization: Bearer <token>
Content-Type: application/json
{"email": "new@example.com", "firstName": "New",
"userType": "default"}
Response example
{
"id": "new-uuid",
"email": "new@example.com",
"firstName": "New",
"isAdmin": false
}
Update user
- Method: PUT
- URL:
/api/v1/users/{userId} - Watch out for: Uses full PUT semantics; omitted optional fields may be reset. Verify field behavior in your Retool version.
Request example
PUT /api/v1/users/abc-123
Authorization: Bearer <token>
Content-Type: application/json
{"isAdmin": true, "isDisabled": false}
Response example
{
"id": "abc-123",
"email": "user@example.com",
"isAdmin": true
}
Delete user
- Method: DELETE
- URL:
/api/v1/users/{userId} - Watch out for: Deletion is permanent and removes the user from all groups and app permissions.
Request example
DELETE /api/v1/users/abc-123
Authorization: Bearer <token>
Response example
{
"success": true
}
List groups
- Method: GET
- URL:
/api/v1/groups - Watch out for: Group IDs are integers, not UUIDs.
Request example
GET /api/v1/groups
Authorization: Bearer <token>
Response example
{
"groups": [
{"id": 1, "name": "Engineering",
"universalAppAccess": "viewer"}
]
}
Add user to group
- Method: POST
- URL:
/api/v1/groups/{groupId}/members - Watch out for: User must already exist in the org before being added to a group.
Request example
POST /api/v1/groups/1/members
Authorization: Bearer <token>
Content-Type: application/json
{"userId": "abc-123"}
Response example
{
"success": true
}
Remove user from group
- Method: DELETE
- URL:
/api/v1/groups/{groupId}/members/{userId} - Watch out for: Removing a user from all groups does not disable the user account.
Request example
DELETE /api/v1/groups/1/members/abc-123
Authorization: Bearer <token>
Response example
{
"success": true
}
Rate limits, pagination, and events
- Rate limits: Retool does not publicly document specific rate limit numbers for the REST API. Limits are enforced but thresholds are not published.
- Rate-limit headers: Unknown
- Retry-After header: Unknown
- Rate-limit notes: No publicly documented rate limit values. Contact Retool support for enterprise-tier limits.
- Pagination method: offset
- Default page size: 100
- Max page size: Not documented
- Pagination pointer: page, pageSize
| Plan | Limit | Concurrent |
|---|---|---|
| Free | 0 | |
| Team | 0 | |
| Business | 0 | |
| Enterprise | 0 |
- Webhooks available: No
- Webhook notes: Retool does not offer native outbound webhooks for user lifecycle events (create, update, delete) via the REST API.
- Alternative event strategy: Use SCIM provisioning with an IdP (Okta, Entra ID) to automate user lifecycle events, or poll the REST API on a schedule.
SCIM API status
SCIM available: Yes
SCIM version: 2.0
Plan required: Enterprise
Endpoint: https://
/scim/v2 Supported operations: GET /Users, GET /Users/{id}, POST /Users, PUT /Users/{id}, PATCH /Users/{id}, DELETE /Users/{id}, GET /Groups, GET /Groups/{id}, POST /Groups, PUT /Groups/{id}, PATCH /Groups/{id}, DELETE /Groups/{id}
Limitations:
- Requires SSO to be configured before SCIM can be enabled.
- Available on Retool Cloud and self-hosted instances running v2.32.1 or later.
- SCIM token is separate from REST API access tokens; generated under Settings → SSO.
- Only Okta and Entra ID (Azure AD) are officially documented as IdP integrations.
- Custom authentication (non-SSO) is not compatible with SCIM provisioning.
Common scenarios
The three highest-value automation scenarios against this API are provisioning, deprovisioning, and SCIM-driven lifecycle management.
Provisioning uses POST /api/v1/users with email, firstName, lastName, and userType, then POST /api/v1/groups/{groupId}/members to assign access. POST /users triggers an invitation email, and SSO-enforced orgs require the user to complete SSO login before any access is active.
Deprovisioning starts by resolving the userId via GET /api/v1/users?email=.... Optionally set isDisabled: true via PUT to block access while preserving audit history, then DELETE /api/v1/users/{userId} for permanent removal.
Deletion is irreversible and strips all group memberships and app permissions immediately.
SCIM-based lifecycle via Okta or Entra ID requires Enterprise plan plus an active SSO configuration. The SCIM token is generated separately under Settings → SSO and is not interchangeable with REST API tokens.
For Entra ID, the SCIM base URL must be manually modified before entry in the Azure app config.
A known Okta gotcha: SCIM group push creates Retool groups by name, which can produce duplicates if same-named groups already exist - pre-create groups in Retool and link via Okta push rules to avoid this.
Provision a new employee and assign to a group
- POST /api/v1/users with email, firstName, lastName, and userType.
- Capture the returned user id from the response.
- POST /api/v1/groups/{groupId}/members with the new userId.
- Verify membership with GET /api/v1/groups/{groupId}/members.
Watch out for: The user receives an invitation email on creation. If SSO is enforced, they must complete SSO login before accessing Retool.
Deprovision a departing employee
- GET /api/v1/users?email=user@example.com to resolve the userId.
- Optionally, PUT /api/v1/users/{userId} with isDisabled: true to immediately block access while retaining audit history.
- DELETE /api/v1/users/{userId} to permanently remove the user and revoke all app permissions.
Watch out for: Deletion is irreversible. Consider disabling first to allow a grace period before permanent removal.
Automate user lifecycle via SCIM with Okta
- Ensure Enterprise plan and SSO (SAML/OIDC) are active in Retool Settings.
- Navigate to Settings → SSO → SCIM and generate a SCIM bearer token.
- In Okta, add the Retool SCIM app, set Base URL to https://
/scim/v2, and paste the SCIM token. - Map Okta profile attributes to SCIM attributes (userName → email, givenName, familyName).
- Assign Okta groups to the Retool app; Okta will push group membership changes to Retool automatically.
- Test provisioning by assigning a test user in Okta and confirming creation in Retool.
Watch out for: SCIM group push in Okta creates Retool groups by name; if a same-named group already exists in Retool, a duplicate may be created. Pre-create groups in Retool and link them via Okta group push rules to avoid duplicates.
Why building this yourself is a trap
Several API behaviors create silent failure modes worth flagging explicitly. PUT /api/v1/users/{userId} uses full PUT semantics - omitted optional fields may be reset, not preserved; verify field behavior against your specific Retool version before running bulk updates.
Group IDs in the REST API are integers; SCIM group IDs are strings - conflating them across systems will cause lookup failures in any identity graph that joins on group ID.
Webhooks for user lifecycle events (create, update, delete) are not available; the only event-driven path is SCIM with an IdP, or scheduled polling of the REST API. Self-hosted instances must be on v2.32.1 or later for the /scim/v2 endpoint to exist - older versions will return 404 with no clear error message.
Automate Retool 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.