Summary and recommendation
Mural's public REST API is available at `https://app.mural.co/api/public/v1` and uses OAuth 2.0 (authorization code flow) or API keys for server-to-server use. Workspace operations require `workspaces:read` and `workspaces:write` scopes; room-level operations require separate `rooms:read` and `rooms:write` scopes.
Note that the `workspaceId` path parameter is the workspace slug, not a UUID - it is found in the workspace URL and is a common source of 404 errors.
Pagination is cursor-based using `nextToken`; the default page size is 25 and the maximum is 100. There is no bulk-invite endpoint - invitations must be issued one at a time via `POST /workspaces/{workspaceId}/members`. Rate limit thresholds are not publicly documented; implement exponential backoff on HTTP 429 and respect the `Retry-After` header.
Webhooks are not available in the public API. Membership change detection requires polling `GET /workspaces/{workspaceId}/members` on a schedule.
API quick reference
| Has user API | Yes |
| Auth method | OAuth 2.0 (authorization code flow); API keys also supported for server-to-server |
| Base URL | Official docs |
| SCIM available | Yes |
| SCIM plan required | Enterprise |
Authentication
Auth method: OAuth 2.0 (authorization code flow); API keys also supported for server-to-server
Setup steps
- Register an application at https://developers.mural.co to obtain a client_id and client_secret.
- Direct users to https://app.mural.co/oauth/authorize with response_type=code, client_id, redirect_uri, and desired scopes.
- Exchange the returned authorization code for an access_token and refresh_token via POST https://app.mural.co/oauth/token.
- Include the access token in requests as Authorization: Bearer
. - Refresh tokens using the refresh_token grant type before expiry.
Required scopes
| Scope | Description | Required for |
|---|---|---|
| identity:read | Read the authenticated user's profile information | GET /users/me |
| workspaces:read | Read workspace details and membership lists | GET /workspaces/{workspaceId}/members |
| workspaces:write | Invite and remove members from a workspace | POST /workspaces/{workspaceId}/members, DELETE /workspaces/{workspaceId}/members/{memberId} |
| rooms:read | Read room membership | GET /workspaces/{workspaceId}/rooms/{roomId}/members |
| rooms:write | Add or remove members from rooms | POST /workspaces/{workspaceId}/rooms/{roomId}/members |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | string | Unique Mural user identifier | system-generated | immutable | Used as memberId in workspace/room endpoints |
| string | User's email address | required | not updatable via REST API | Primary identifier for invitations | |
| firstName | string | User's first name | optional | read-only via REST; updatable via SCIM | |
| lastName | string | User's last name | optional | read-only via REST; updatable via SCIM | |
| role | string | Workspace role: ADMIN, MEMBER, GUEST | optional (defaults to MEMBER) | patchable | Roles are workspace-scoped |
| avatarUrl | string | URL to user's avatar image | system-generated | read-only | |
| createdAt | integer (epoch ms) | Timestamp when user joined the workspace | system-generated | immutable | |
| lastActiveAt | integer (epoch ms) | Timestamp of last activity | system-generated | system-managed | |
| status | string | Membership status: ACTIVE, PENDING, DEACTIVATED | system-generated | managed via SCIM active flag | PENDING indicates invitation not yet accepted |
Core endpoints
Get authenticated user
- Method: GET
- URL:
https://app.mural.co/api/public/v1/users/me - Watch out for: Returns the token owner's profile only; not a directory lookup endpoint.
Request example
GET /api/public/v1/users/me
Authorization: Bearer <access_token>
Response example
{
"value": {
"id": "usr_abc123",
"email": "user@example.com",
"firstName": "Jane",
"lastName": "Doe"
}
}
List workspace members
- Method: GET
- URL:
https://app.mural.co/api/public/v1/workspaces/{workspaceId}/members - Watch out for: Paginate using nextToken until it is absent or null. Guests may not appear depending on workspace settings.
Request example
GET /api/public/v1/workspaces/myworkspace/members?limit=50
Authorization: Bearer <access_token>
Response example
{
"value": [
{"id":"usr_abc","email":"a@co.com","role":"MEMBER"}
],
"nextToken": "tok_xyz"
}
Get workspace member
- Method: GET
- URL:
https://app.mural.co/api/public/v1/workspaces/{workspaceId}/members/{memberId} - Watch out for: Returns 404 if the user is not a member of the specified workspace.
Request example
GET /api/public/v1/workspaces/myworkspace/members/usr_abc
Authorization: Bearer <access_token>
Response example
{
"value": {
"id": "usr_abc",
"email": "a@co.com",
"role": "MEMBER",
"status": "ACTIVE"
}
}
Invite member to workspace
- Method: POST
- URL:
https://app.mural.co/api/public/v1/workspaces/{workspaceId}/members - Watch out for: Invited users receive an email; status is PENDING until accepted. Seat limits apply based on plan.
Request example
POST /api/public/v1/workspaces/myworkspace/members
Content-Type: application/json
{"email":"new@co.com","role":"MEMBER"}
Response example
{
"value": {
"id": "usr_new",
"email": "new@co.com",
"status": "PENDING"
}
}
Remove member from workspace
- Method: DELETE
- URL:
https://app.mural.co/api/public/v1/workspaces/{workspaceId}/members/{memberId} - Watch out for: Removing a member does not delete their Mural account; it only removes workspace access.
Request example
DELETE /api/public/v1/workspaces/myworkspace/members/usr_abc
Authorization: Bearer <access_token>
Response example
HTTP 204 No Content
List room members
- Method: GET
- URL:
https://app.mural.co/api/public/v1/workspaces/{workspaceId}/rooms/{roomId}/members - Watch out for: Room membership is a subset of workspace membership; users must be workspace members first.
Request example
GET /api/public/v1/workspaces/myworkspace/rooms/room_123/members
Authorization: Bearer <access_token>
Response example
{
"value": [
{"id":"usr_abc","role":"EDITOR"}
],
"nextToken": null
}
Add member to room
- Method: POST
- URL:
https://app.mural.co/api/public/v1/workspaces/{workspaceId}/rooms/{roomId}/members - Watch out for: The user must already be a workspace member; otherwise returns 400.
Request example
POST /api/public/v1/workspaces/myworkspace/rooms/room_123/members
Content-Type: application/json
{"memberId":"usr_abc","role":"EDITOR"}
Response example
{
"value": {
"id": "usr_abc",
"role": "EDITOR"
}
}
Update workspace member role
- Method: PATCH
- URL:
https://app.mural.co/api/public/v1/workspaces/{workspaceId}/members/{memberId} - Watch out for: Only role is patchable via REST API; profile fields (name, email) require SCIM or user self-service.
Request example
PATCH /api/public/v1/workspaces/myworkspace/members/usr_abc
Content-Type: application/json
{"role":"ADMIN"}
Response example
{
"value": {
"id": "usr_abc",
"role": "ADMIN"
}
}
Rate limits, pagination, and events
- Rate limits: Mural enforces per-application rate limits on the public API. Exact numeric limits are not publicly documented; headers indicate remaining quota.
- Rate-limit headers: Yes
- Retry-After header: Yes
- Rate-limit notes: When rate limited, the API returns HTTP 429. Respect Retry-After header before retrying.
- Pagination method: token
- Default page size: 25
- Max page size: 100
- Pagination pointer: nextToken
| Plan | Limit | Concurrent |
|---|---|---|
| All plans (public API) | Not publicly specified; contact Mural for enterprise quotas | 0 |
- Webhooks available: No
- Webhook notes: Mural's public API documentation does not describe outbound webhook support for user or membership events as of the research date.
- Alternative event strategy: Poll GET /workspaces/{workspaceId}/members on a schedule to detect membership changes.
SCIM API status
SCIM available: Yes
SCIM version: 2.0
Plan required: Enterprise
Endpoint: https://app.mural.co/scim/v2
Supported operations: GET /Users (list users), GET /Users/{id} (get user), POST /Users (provision user), PUT /Users/{id} (replace user), PATCH /Users/{id} (update user / deactivate), DELETE /Users/{id} (deprovision user), GET /Groups (list groups/rooms), POST /Groups (create group), PATCH /Groups/{id} (update group membership), DELETE /Groups/{id} (delete group)
Limitations:
- Requires Enterprise plan and SSO (SAML) configured as a prerequisite.
- Supported IdPs: Okta and Microsoft Entra ID (Azure AD); other IdPs may work but are not officially documented.
- SCIM token is a long-lived bearer token generated in workspace admin settings; rotate manually.
- Deprovisioning sets user status to DEACTIVATED but does not permanently delete the account.
- Group sync maps to Mural rooms; room creation via SCIM may have naming constraints.
Common scenarios
Three integration patterns cover the majority of identity lifecycle use cases.
For onboarding, POST /workspaces/{workspaceId}/members with {email, role: 'MEMBER'} creates the invitation. The user's status remains PENDING until they accept - poll GET /workspaces/{workspaceId}/members/{memberId} for status == 'ACTIVE' before attempting room assignment via POST /workspaces/{workspaceId}/rooms/{roomId}/members. On Enterprise, SCIM provisioning bypasses the pending state entirely.
For offboarding via SCIM (Enterprise only), the IdP sends PATCH /Users/{id} with {active: false} to https://app.mural.co/scim/v2, setting the user to DEACTIVATED. A subsequent DELETE /Users/{id} removes the SCIM-managed record. Neither operation deletes owned murals - content reassignment remains a manual admin step.
For auditing, paginate GET /workspaces/{workspaceId}/members?limit=100 using nextToken until the token is absent. Inspect id, email, role, status, and lastActiveAt fields per member object. The lastActiveAt field (epoch ms) is the only programmatic signal for inactivity - there is no dedicated activity API.
Onboard a new employee to workspace and room
- POST /workspaces/{workspaceId}/members with {email, role: 'MEMBER'} to invite the user.
- Poll GET /workspaces/{workspaceId}/members/{memberId} until status == 'ACTIVE' (user accepted invite).
- POST /workspaces/{workspaceId}/rooms/{roomId}/members with {memberId, role: 'EDITOR'} to grant room access.
Watch out for: User must accept the invitation before room membership can be assigned; automate the status check or use SCIM provisioning (Enterprise) to bypass the pending state.
Deprovision a departing employee via SCIM
- Trigger deprovisioning in the IdP (Okta or Entra ID) for the user.
- IdP sends PATCH /Users/{id} with {active: false} to the Mural SCIM endpoint.
- Mural sets the user's status to DEACTIVATED, revoking workspace access.
- Optionally send DELETE /Users/{id} to fully remove the SCIM-managed user record.
Watch out for: SCIM deprovisioning requires Enterprise plan with SSO active. Deactivation does not delete murals owned by the user; content reassignment must be handled manually by a workspace admin.
Audit all workspace members and their roles
- GET /workspaces/{workspaceId}/members?limit=100 and collect the response value array.
- If nextToken is present in the response, repeat the request with nextToken as a query parameter.
- Continue until nextToken is null or absent.
- Aggregate all member objects and inspect id, email, role, and status fields.
Watch out for: Default page size is 25; always set limit=100 to minimize round trips. Large workspaces may require many pages; account for rate limiting with backoff.
Why building this yourself is a trap
The most significant architectural caveat is the SCIM/REST independence: changes made via SCIM are not reflected in OAuth token scopes and vice versa. Teams building an identity graph across Mural workspaces must reconcile both surfaces to get a complete membership picture - relying on the REST API alone will miss SCIM-managed state on Enterprise tenants.
OAuth access tokens are short-lived; failing to implement refresh_token rotation will produce silent 401 failures in long-running automation. Guest users (external collaborators) may not appear in standard GET /workspaces/{workspaceId}/members responses depending on workspace configuration, creating gaps in any identity graph built from that endpoint alone.
SCIM group sync maps to Mural rooms, not workspaces - a distinction that matters when modeling org structure. Room membership via SCIM requires the user to already be a workspace member; the API returns 400 otherwise, and SCIM does not automatically handle the sequencing.
Teams using an MCP server with 60+ deep IT/identity integrations to orchestrate cross-app provisioning should treat Mural's two-layer membership model (workspace → room) as requiring explicit sequencing logic, not a single provisioning call.
Automate Mural 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.