Summary and recommendation
Pulumi Cloud exposes a REST API under `https://api.pulumi.com/api` authenticated via Bearer token (`Authorization: token <YOUR_TOKEN>`). All org-scoped operations require the token owner to hold the org Admin role. The `{org}` path parameter is the org's URL slug, not its display name - a common source of 404s.
Pagination uses a `continuationToken` query parameter; a missing token in the response signals the final page. Rate limit thresholds are not publicly documented; implement exponential backoff on HTTP 429 unconditionally.
For identity graph use cases - mapping users to teams, stacks, and roles across the org - the `GET /api/orgs/{org}/members` and `GET /api/orgs/{org}/teams` endpoints are the primary traversal points. The user object returns `githubLogin`, `email`, `role`, and `teamMembership`, giving enough signal to reconstruct org-wide access topology.
There is no public invite endpoint; new user provisioning must go through the UI or SCIM.
SCIM 2.0 is available at `https://api.pulumi.com/scim/v2/{org}` on Enterprise plan, with full Users and Groups CRUD. SCIM Groups map 1:1 to Pulumi Teams. The SCIM token is a separate org-level credential generated in SCIM settings - it is distinct from personal access tokens and must not be substituted.
SSO (SAML) must be active before SCIM can be enabled.
API quick reference
| Has user API | Yes |
| Auth method | Bearer token (Pulumi Cloud access token passed as Authorization header) |
| Base URL | Official docs |
| SCIM available | Yes |
| SCIM plan required | Enterprise |
Authentication
Auth method: Bearer token (Pulumi Cloud access token passed as Authorization header)
Setup steps
- Log in to Pulumi Cloud (app.pulumi.com).
- Navigate to your user avatar → Access Tokens.
- Click 'Create token', give it a name, and copy the generated token.
- Pass the token in API requests as the header: Authorization: token
. - For org-scoped operations, ensure the token belongs to a user with appropriate org role (Admin or Member).
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| githubLogin | string | User's GitHub login / Pulumi Cloud username | N/A (read-only, set at registration) | not updatable via API | Used as the primary identifier in most endpoints |
| name | string | Display name of the user | N/A | not updatable via API | |
| avatarUrl | string | URL to the user's avatar image | N/A | not updatable via API | |
| string | Primary email address of the user | N/A | not updatable via API | Returned in user profile responses | |
| role | string | User's role within the organization (admin or member) | set on invite | PATCH /api/orgs/{org}/members/{user} | Values: 'admin' or 'member' |
| teamMembership | array | Teams the user belongs to within the org | via team membership endpoint | via team membership endpoint | Managed separately through team endpoints |
Core endpoints
List organization members
- Method: GET
- URL:
https://api.pulumi.com/api/orgs/{org}/members - Watch out for: Returns only members of the specified org; token must belong to an org admin.
Request example
GET /api/orgs/myorg/members
Authorization: token pul-abc123
Response example
{
"members": [
{
"role": "admin",
"user": {
"githubLogin": "jdoe",
"name": "Jane Doe",
"avatarUrl": "https://..."
}
}
]
}
Get organization member
- Method: GET
- URL:
https://api.pulumi.com/api/orgs/{org}/members/{username} - Watch out for: Username is the Pulumi Cloud login handle, not email.
Request example
GET /api/orgs/myorg/members/jdoe
Authorization: token pul-abc123
Response example
{
"role": "member",
"user": {
"githubLogin": "jdoe",
"name": "Jane Doe",
"avatarUrl": "https://..."
}
}
Update organization member role
- Method: PATCH
- URL:
https://api.pulumi.com/api/orgs/{org}/members/{username} - Watch out for: Only 'admin' and 'member' are valid role values.
Request example
PATCH /api/orgs/myorg/members/jdoe
Authorization: token pul-abc123
Content-Type: application/json
{"role": "admin"}
Response example
HTTP 200 OK
{}
Remove organization member
- Method: DELETE
- URL:
https://api.pulumi.com/api/orgs/{org}/members/{username} - Watch out for: Removing a member does not delete their Pulumi account; it only removes org membership.
Request example
DELETE /api/orgs/myorg/members/jdoe
Authorization: token pul-abc123
Response example
HTTP 204 No Content
List teams in organization
- Method: GET
- URL:
https://api.pulumi.com/api/orgs/{org}/teams - Watch out for: Teams are an Enterprise/Team plan feature; endpoint may return empty on Individual plan.
Request example
GET /api/orgs/myorg/teams
Authorization: token pul-abc123
Response example
{
"teams": [
{"kind": "pulumi", "name": "platform-team",
"displayName": "Platform Team"}
]
}
Add member to team
- Method: POST
- URL:
https://api.pulumi.com/api/orgs/{org}/teams/{team}/members - Watch out for: User must already be an org member before being added to a team.
Request example
POST /api/orgs/myorg/teams/platform-team/members
Authorization: token pul-abc123
Content-Type: application/json
{"memberLogin": "jdoe"}
Response example
HTTP 200 OK
{}
Remove member from team
- Method: DELETE
- URL:
https://api.pulumi.com/api/orgs/{org}/teams/{team}/members/{username} - Watch out for: Does not remove the user from the organization, only from the team.
Request example
DELETE /api/orgs/myorg/teams/platform-team/members/jdoe
Authorization: token pul-abc123
Response example
HTTP 204 No Content
List organization access tokens
- Method: GET
- URL:
https://api.pulumi.com/api/orgs/{org}/tokens - Watch out for: Token values are not returned after creation; only metadata is listed.
Request example
GET /api/orgs/myorg/tokens
Authorization: token pul-abc123
Response example
{
"tokens": [
{"id": "tok-xyz", "description": "CI token",
"lastUsed": "2024-01-15T10:00:00Z"}
]
}
Rate limits, pagination, and events
Rate limits: Pulumi Cloud REST API enforces rate limits but does not publicly document specific numeric thresholds per plan tier.
Rate-limit headers: Unknown
Retry-After header: Unknown
Rate-limit notes: No publicly documented rate limit values found in official docs. Implement exponential backoff on HTTP 429 responses.
Pagination method: token
Default page size: Not documented
Max page size: Not documented
Pagination pointer: continuationToken
Webhooks available: No
Webhook notes: Pulumi Cloud does not expose a general-purpose webhook system for user-management events in its official documentation.
Alternative event strategy: Use the REST API to poll for membership changes, or rely on SCIM provisioning events from your IdP.
SCIM API status
SCIM available: Yes
SCIM version: 2.0
Plan required: Enterprise
Endpoint: https://api.pulumi.com/scim/v2/{org}
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 Enterprise plan.
- SSO (SAML) must be configured and enabled before SCIM can be activated.
- Supported IdPs documented: Okta and Microsoft Entra ID (Azure AD).
- SCIM Groups map to Pulumi Teams; team names must be unique within the org.
- Deprovisioning a SCIM user removes them from the org but does not delete the Pulumi account.
- SCIM token is a separate org-level token generated in the Pulumi Cloud SCIM settings page.
Common scenarios
Three automation scenarios are well-supported by the current API surface.
Deprovision via REST: Call DELETE /api/orgs/{org}/members/{username} with an Admin token, then confirm with a GET expecting a 404. Critical caveat: this call does not revoke the user's personal access tokens - those remain valid and must be audited and revoked separately.
Provision via SCIM (Okta): Generate a SCIM token in org SCIM settings, configure Okta with base URL https://api.pulumi.com/scim/v2/{org}, enable Push Users and Push Groups. Okta group pushes create Pulumi Teams automatically; team name collisions with pre-existing Pulumi Teams will cause provisioning failures and must be resolved before sync.
Role promotion via REST: PATCH /api/orgs/{org}/members/{username} with body {"role": "admin"}. Only admin and member are valid values. The target user must have already accepted org membership; the endpoint will reject promotion of pending invitees.
Deprovision a user via REST API
- Authenticate with an org Admin access token.
- Call DELETE /api/orgs/{org}/members/{username} to remove the user from the organization.
- Optionally, call DELETE /api/orgs/{org}/teams/{team}/members/{username} for each team first (membership is removed automatically on org removal).
- Verify removal by calling GET /api/orgs/{org}/members/{username} and confirming 404.
Watch out for: Removing a member via REST does not revoke their personal Pulumi access tokens; those must be managed separately or via SCIM deprovisioning.
Automate user provisioning via SCIM (Okta)
- Ensure Enterprise plan is active and SAML SSO is configured for the org.
- In Pulumi Cloud org settings, navigate to SCIM and generate a SCIM access token.
- In Okta, add the Pulumi app and configure SCIM provisioning with base URL https://api.pulumi.com/scim/v2/{org} and Bearer token auth.
- Enable 'Push Users' and 'Push Groups' in Okta to sync users and teams to Pulumi.
- Assign users/groups in Okta; Pulumi will auto-provision org membership and team assignments.
Watch out for: SCIM Groups in Okta map to Pulumi Teams; the team must not already exist with a conflicting name in Pulumi Cloud.
Promote a member to org Admin
- Authenticate with an existing org Admin access token.
- Call PATCH /api/orgs/{org}/members/{username} with body {"role": "admin"}.
- Confirm the change by calling GET /api/orgs/{org}/members/{username} and verifying role is 'admin'.
Watch out for: Only existing org members can be promoted; the user must have accepted org membership first.
Why building this yourself is a trap
The most consequential API gap is the absence of token lifecycle management in the REST surface: DELETE /api/orgs/{org}/members/{username} removes org membership but leaves all personal access tokens issued to that user fully operational. Any automation pipeline that treats the DELETE response as a complete offboarding signal is incorrect.
A secondary trap is the dual base-path architecture - REST lives under /api/orgs/{org} while SCIM lives under /scim/v2/{org}; mixing these paths produces authentication errors that are not always self-explanatory.
Finally, webhooks for user-management events are not available; any identity graph that needs to stay current must poll GET /api/orgs/{org}/members on a schedule or rely on IdP-side SCIM event logs as the authoritative change feed.
Automate Pulumi 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.