Summary and recommendation
Medusa's Admin REST API exposes full CRUD for admin users under /admin/users, with authentication via Bearer JWT obtained from POST /auth/user/emailpass. A critical v2 caveat: user record creation (POST /admin/users) and auth identity creation (POST /auth/user/emailpass/register) are decoupled-a user record without a linked auth identity cannot log in.
Admin users and storefront customers are entirely separate entities; /admin/users returns only dashboard admins, while /admin/customers holds storefront customer records. Pagination uses offset/limit with a default page size of 20; no documented maximum page size exists in the open-source core.
API quick reference
| Has user API | Yes |
| Auth method | Bearer JWT token (session cookie also supported); API key authentication available for server-to-server calls |
| Base URL | Official docs |
| SCIM available | No |
Authentication
Auth method: Bearer JWT token (session cookie also supported); API key authentication available for server-to-server calls
Setup steps
- POST /auth/user/emailpass with email and password to obtain a JWT token
- Include the token as Authorization: Bearer
header on subsequent requests - Alternatively, use publishable API keys for storefront calls or secret API keys for admin server-to-server calls configured in Medusa dashboard or via environment variable MEDUSA_ADMIN_API_KEY
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | string | Unique user identifier (prefixed 'user_') | auto-generated | immutable | |
| string | User's email address | required | optional | Must be unique across admin users | |
| first_name | string|null | User's first name | optional | optional | |
| last_name | string|null | User's last name | optional | optional | |
| avatar_url | string|null | URL to user avatar image | optional | optional | |
| metadata | object|null | Arbitrary key-value pairs for custom data | optional | optional | |
| created_at | datetime | ISO 8601 timestamp of creation | auto-generated | immutable | |
| updated_at | datetime | ISO 8601 timestamp of last update | auto-generated | auto-updated | |
| deleted_at | datetime|null | Soft-delete timestamp | null | set on delete | Medusa uses soft deletes |
Core endpoints
List Users
- Method: GET
- URL:
/admin/users - Watch out for: Returns only admin (dashboard) users, not storefront customers. Customer records live under /admin/customers.
Request example
GET /admin/users?limit=20&offset=0
Authorization: Bearer <token>
Response example
{
"users": [{"id":"user_01","email":"admin@example.com","first_name":"Jane"}],
"count": 1,
"offset": 0,
"limit": 20
}
Get User
- Method: GET
- URL:
/admin/users/{id}
Request example
GET /admin/users/user_01
Authorization: Bearer <token>
Response example
{
"user": {
"id": "user_01",
"email": "admin@example.com",
"first_name": "Jane",
"last_name": "Doe"
}
}
Create User
- Method: POST
- URL:
/admin/users - Watch out for: In Medusa v2, creating a user via this endpoint does not automatically create auth credentials. A separate auth identity must be registered via the Auth module (POST /auth/user/emailpass/register) to allow login.
Request example
POST /admin/users
Authorization: Bearer <token>
{
"email": "newuser@example.com",
"first_name": "John",
"last_name": "Smith"
}
Response example
{
"user": {
"id": "user_02",
"email": "newuser@example.com",
"first_name": "John"
}
}
Update User
- Method: POST
- URL:
/admin/users/{id} - Watch out for: Medusa v2 Admin API uses POST (not PATCH) for updates on some resource types. Verify against the versioned API reference for your Medusa version.
Request example
POST /admin/users/user_02
Authorization: Bearer <token>
{
"first_name": "Jonathan",
"metadata": {"department": "ops"}
}
Response example
{
"user": {
"id": "user_02",
"first_name": "Jonathan",
"metadata": {"department": "ops"}
}
}
Delete User
- Method: DELETE
- URL:
/admin/users/{id} - Watch out for: Soft-delete only; deleted_at is set. Auth identities linked to the user are not automatically removed.
Request example
DELETE /admin/users/user_02
Authorization: Bearer <token>
Response example
{
"id": "user_02",
"object": "user",
"deleted": true
}
Get Logged-in User (Me)
- Method: GET
- URL:
/admin/users/me
Request example
GET /admin/users/me
Authorization: Bearer <token>
Response example
{
"user": {
"id": "user_01",
"email": "admin@example.com"
}
}
Authenticate (Login)
- Method: POST
- URL:
/auth/user/emailpass - Watch out for: This endpoint is on the /auth prefix, not /admin. The returned JWT must be passed as Bearer token to all admin endpoints.
Request example
POST /auth/user/emailpass
{
"email": "admin@example.com",
"password": "supersecret"
}
Response example
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Invite User
- Method: POST
- URL:
/admin/invites - Watch out for: Invite tokens expire. The invitee must POST /admin/invites/accept with the token and their credentials to complete registration.
Request example
POST /admin/invites
Authorization: Bearer <token>
{
"email": "invite@example.com"
}
Response example
{
"invite": {
"id": "invite_01",
"email": "invite@example.com",
"token": "abc123...",
"accepted": false
}
}
Rate limits, pagination, and events
Rate limits: No built-in rate limiting in the open-source Medusa core. Rate limiting must be implemented at the infrastructure layer (e.g., reverse proxy, API gateway). Medusa Cloud tiers may impose limits not publicly documented.
Rate-limit headers: No
Retry-After header: No
Rate-limit notes: Self-hosted deployments have no default rate limits. Implement via middleware or reverse proxy (nginx, Cloudflare, etc.).
Pagination method: offset
Default page size: 20
Max page size: Not documented
Pagination pointer: offset / limit
Webhooks available: Yes
Webhook notes: Medusa v2 supports subscribing to events via its event bus module. Webhooks to external URLs are not natively built-in but can be implemented using the Notification Module or custom subscribers.
Alternative event strategy: Use Medusa's Subscriber pattern in custom modules to react to user events programmatically, or integrate a notification provider (e.g., SendGrid plugin) to trigger external calls.
Webhook events: user.created, user.updated, user.deleted, invite.created, invite.accepted, invite.resent
SCIM API status
- SCIM available: No
- SCIM version: Not documented
- Plan required: Not documented
- Endpoint: Not documented
Limitations:
- No native SCIM 2.0 support in Medusa core or Medusa Cloud as of 2025
- SSO is not natively supported; requires custom Auth Module provider implementation
- SCIM provisioning would require a fully custom implementation using Medusa's User Module service and Auth Module
Common scenarios
Three scenarios cover the primary provisioning lifecycle.
First, programmatic admin provisioning requires two sequential calls: register auth credentials via the Auth Module, then create the user record, then explicitly link the auth identity if auto-linking does not occur-skipping any step produces a user who exists in the identity graph but cannot authenticate.
Second, the invite flow (POST /admin/invites) generates a token that must be delivered out-of-band; Medusa does not send email natively, so teams must attach a subscriber on the invite. created event or use a notification plugin.
Third, offboarding via DELETE /admin/users/{id} is a soft delete only-deleted_at is set but the auth identity remains active and existing JWTs are not invalidated, so token revocation or short expiry windows must be enforced separately at the infrastructure layer to guarantee immediate access termination.
Provision a new admin user programmatically
- POST /auth/user/emailpass/register with {email, password} to create auth credentials
- POST /admin/users with {email, first_name, last_name} to create the user record
- Link the auth identity to the user record using the Auth Module's linkIdentities workflow if not auto-linked
- Verify by GET /admin/users/{id}
Watch out for: Auth identity and user record creation are separate steps in v2. Skipping the auth registration means the user cannot log in even though a user record exists.
Invite an external user to the admin dashboard
- POST /admin/invites with {email} to generate an invite token
- Deliver the token to the invitee (Medusa does not send email natively; use a notification plugin or custom subscriber on invite.created event)
- Invitee POSTs /admin/invites/accept with {token, first_name, last_name, password} to complete registration
- Verify user appears in GET /admin/users
Watch out for: Invite tokens expire. If the invitee does not accept in time, POST /admin/invites/{id}/resent to issue a new token.
Soft-delete and clean up a departed admin user
- DELETE /admin/users/{id} to soft-delete the user record (sets deleted_at)
- Optionally remove the associated auth identity via the Auth Module service (deleteAuthIdentity) to prevent any residual login capability
- Confirm deletion by attempting GET /admin/users/{id} - should return 404 or empty
Watch out for: Soft-delete alone does not invalidate existing JWT tokens. Implement token revocation or short JWT expiry windows to ensure immediate access termination.
Why building this yourself is a trap
The most dangerous assumption when automating Medusa user management is treating the identity graph as a single object. In v2, a user record, an auth identity, and any linked session tokens are three distinct entities that must each be managed independently-create, update, and delete operations on /admin/users do not cascade to the Auth Module.
There is no native SCIM 2.0 support and no native SSO; any identity provider integration requires a fully custom Auth Module provider implementation. The open-source core has no built-in rate limiting, so automated provisioning scripts running against self-hosted instances must implement their own throttling at the reverse proxy or API gateway layer.
Medusa Cloud API behavior and any cloud-specific rate limits are not fully publicly documented, adding an additional caveat for teams building against hosted deployments.
Automate Medusa 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.