Summary and recommendation
The WordPress REST API exposes user lifecycle operations under https://<your-site>/wp-json/wp/v2/users. Authentication for programmatic access uses Application Passwords (HTTP Basic Auth over HTTPS, built-in since WordPress 5.6); OAuth 2.0 is available only via third-party plugins such as WP OAuth Server.
Application Passwords will not generate or function over plain HTTP by default - HTTPS is a hard requirement.
Capability enforcement is role-based at the API layer. Listing all users, creating users, updating other users' records, or deleting users all require the edit_users capability, which maps to the Administrator role. Unauthenticated GET /users requests return only users with at least one published post, and sensitive fields (email, roles, capabilities) are suppressed entirely.
WordPress core imposes no native rate limits on the REST API. Rate limiting is entirely host- and infrastructure-dependent; no standard rate-limit response headers are emitted by core. WordPress VIP enforces platform-level limits, but specific thresholds are not publicly documented.
API quick reference
| Has user API | Yes |
| Auth method | Application Passwords (HTTP Basic Auth) for programmatic access; Cookie + Nonce for browser-based requests; OAuth 2.0 via third-party plugins (e.g., WP OAuth Server) |
| Base URL | Official docs |
| SCIM available | No |
| SCIM plan required | No native SCIM support in WordPress core or WordPress VIP. SCIM provisioning requires a third-party plugin (e.g., 'SCIM User Provisioning' plugins) or custom development. |
Authentication
Auth method: Application Passwords (HTTP Basic Auth) for programmatic access; Cookie + Nonce for browser-based requests; OAuth 2.0 via third-party plugins (e.g., WP OAuth Server)
Setup steps
- Ensure WordPress 5.6+ is installed (Application Passwords are built-in).
- Log in as an admin and navigate to Users > Profile.
- Scroll to 'Application Passwords', enter a name, and click 'Add New Application Password'.
- Copy the generated password (shown only once).
- Encode credentials as Base64: base64('
: '). - Include header in requests: Authorization: Basic
. - For OAuth 2.0, install a plugin such as 'WP OAuth Server' and configure client credentials separately.
Required scopes
| Scope | Description | Required for |
|---|---|---|
| read (no auth) | Public user data (name, slug, avatar) is readable without authentication on sites with public REST API enabled. | GET /users (public fields only) |
| authenticated user | Authenticated requests expose additional fields (email, registered_date, capabilities) for the current user. | GET /users/me, GET /users/:id (own record) |
| administrator role | WordPress 'administrator' capability (edit_users) required to list all users, create users, update other users, or delete users. | POST /users, PUT/PATCH /users/:id (others), DELETE /users/:id |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | integer | Unique identifier for the user. | auto-assigned | read-only | Used as path parameter for single-user operations. |
| username | string | Login name for the user. | required | read-only after creation | Cannot be changed via REST API after account creation. |
| name | string | Display name for the user. | optional | writable | Defaults to username if not provided. |
| first_name | string | First name of the user. | optional | writable | Stored in user meta. |
| last_name | string | Last name of the user. | optional | writable | Stored in user meta. |
| string | Email address of the user. | required | writable | Must be unique. Requires authentication to read. | |
| url | string (URI) | URL of the user's website. | optional | writable | |
| description | string | Biographical info / bio. | optional | writable | |
| link | string (URI) | Author archive URL for the user. | auto-generated | read-only | |
| locale | string | Locale for the user. | optional | writable | Requires edit_users capability to set for other users. |
| nickname | string | Nickname for the user. | optional | writable | |
| slug | string | Alphanumeric identifier (URL-friendly) for the user. | optional | writable | Defaults to sanitized username. |
| registered_date | string (datetime) | Registration date/time in ISO 8601. | auto-assigned | read-only | Requires authentication to read. |
| roles | array of strings | Roles assigned to the user (e.g., ['editor']). | optional | writable | Requires edit_users capability. Only one role is typically active. |
| password | string | Password for the user. | required | writable | Write-only; never returned in responses. |
| capabilities | object | All capabilities assigned to the user. | derived from roles | read-only via API | Requires authentication to read. |
| extra_capabilities | object | Any extra capabilities added directly to the user. | n/a | read-only via API | Requires authentication to read. |
| avatar_urls | object | Avatar URLs keyed by size (24, 48, 96). | auto (Gravatar) | read-only via core API | Gravatar-based; custom avatars require plugins. |
| meta | object | Meta fields registered for the user. | optional | writable | Only meta registered via register_meta() with show_in_rest=true are exposed. |
Core endpoints
List Users
- Method: GET
- URL:
/wp/v2/users - Watch out for: Without authentication, only publicly visible users (those with published posts) are returned, and sensitive fields (email, roles) are omitted.
Request example
GET /wp-json/wp/v2/users?per_page=10&page=1
Authorization: Basic <base64_credentials>
Response example
[
{
"id": 1,
"name": "Jane Doe",
"slug": "janedoe",
"email": "jane@example.com",
"roles": ["administrator"]
}
]
Get Current User
- Method: GET
- URL:
/wp/v2/users/me - Watch out for: Returns 401 if request is unauthenticated.
Request example
GET /wp-json/wp/v2/users/me
Authorization: Basic <base64_credentials>
Response example
{
"id": 5,
"username": "janedoe",
"email": "jane@example.com",
"roles": ["editor"],
"registered_date": "2023-01-15T10:00:00"
}
Get Single User
- Method: GET
- URL:
/wp/v2/users/{id} - Watch out for: Non-admin users can only retrieve their own full record; fetching another user's private fields requires edit_users capability.
Request example
GET /wp-json/wp/v2/users/5
Authorization: Basic <base64_credentials>
Response example
{
"id": 5,
"name": "Jane Doe",
"email": "jane@example.com",
"roles": ["editor"]
}
Create User
- Method: POST
- URL:
/wp/v2/users - Watch out for: Requires administrator role (create_users capability). username cannot be changed after creation.
Request example
POST /wp-json/wp/v2/users
Authorization: Basic <base64_credentials>
Content-Type: application/json
{"username":"newuser","email":"new@example.com","password":"Str0ng!","roles":["subscriber"]}
Response example
{
"id": 12,
"username": "newuser",
"email": "new@example.com",
"roles": ["subscriber"]
}
Update User
- Method: POST
- URL:
/wp/v2/users/{id} - Watch out for: WordPress REST API uses POST (not PATCH/PUT) for updates to existing resources. Changing roles requires edit_users capability.
Request example
POST /wp-json/wp/v2/users/12
Authorization: Basic <base64_credentials>
Content-Type: application/json
{"first_name":"New","roles":["editor"]}
Response example
{
"id": 12,
"first_name": "New",
"roles": ["editor"]
}
Delete User
- Method: DELETE
- URL:
/wp/v2/users/{id} - Watch out for: The 'reassign' query parameter (ID of another user) is REQUIRED to reassign the deleted user's posts; omitting it returns a 400 error.
Request example
DELETE /wp-json/wp/v2/users/12?reassign=1
Authorization: Basic <base64_credentials>
Response example
{
"deleted": true,
"previous": {
"id": 12,
"username": "newuser"
}
}
List Users with Role Filter
- Method: GET
- URL:
/wp/v2/users?roles=editor - Watch out for: The 'roles' filter requires administrator authentication; unauthenticated or non-admin requests ignore this parameter.
Request example
GET /wp-json/wp/v2/users?roles=editor&per_page=20
Authorization: Basic <base64_credentials>
Response example
[
{
"id": 7,
"name": "Bob Smith",
"roles": ["editor"]
}
]
Get User by Slug
- Method: GET
- URL:
/wp/v2/users?slug={slug} - Watch out for: Returns an array even for a single match. Returns empty array if user has no published posts and request is unauthenticated.
Request example
GET /wp-json/wp/v2/users?slug=janedoe
Authorization: Basic <base64_credentials>
Response example
[
{
"id": 5,
"slug": "janedoe",
"name": "Jane Doe"
}
]
Rate limits, pagination, and events
- Rate limits: WordPress core does not impose REST API rate limits natively. Rate limiting depends on hosting infrastructure, server-level configuration, or plugins (e.g., Jetpack, WP REST API Rate Limit). WordPress VIP enforces platform-level rate limits.
- Rate-limit headers: No
- Retry-After header: No
- Rate-limit notes: No standard rate-limit response headers are emitted by WordPress core. Hosts may return HTTP 429 with a Retry-After header at the server/CDN layer.
- Pagination method: offset
- Default page size: 10
- Max page size: 100
- Pagination pointer: page / per_page
| Plan | Limit | Concurrent |
|---|---|---|
| WordPress.org (self-hosted) | No built-in limit; host/server dependent | 0 |
| WordPress VIP | Platform-enforced; specific limits not publicly documented | 0 |
- Webhooks available: No
- Webhook notes: WordPress core does not provide native outbound webhooks for user management events. There is no built-in mechanism to push notifications on user creation, update, or deletion.
- Alternative event strategy: Use WordPress action hooks (e.g., user_register, profile_update, delete_user) in custom plugin code to trigger outbound HTTP requests, or install a plugin such as WP Webhooks or Uncanny Automator to configure webhook delivery for user events.
SCIM API status
- SCIM available: No
- SCIM version: Not documented
- Plan required: No native SCIM support in WordPress core or WordPress VIP. SCIM provisioning requires a third-party plugin (e.g., 'SCIM User Provisioning' plugins) or custom development.
- Endpoint: Not documented
Limitations:
- No native SCIM 2.0 endpoint in WordPress core.
- WordPress VIP does not provide a managed SCIM endpoint.
- SCIM support requires a third-party plugin or custom REST API extension.
- Plugin-based SCIM implementations vary in compliance and supported operations.
Common scenarios
Provisioning a new account: POST /wp-json/wp/v2/users with username, email, password, and roles in the request body. The username field is immutable after creation - there is no rename operation via the REST API. Capture the returned id immediately for all subsequent operations.
Role promotion: Resolve the user's numeric ID first via GET /wp-json/wp/v2/users?slug={slug} (returns an array even for a single match), then POST /wp-json/wp/v2/users/{id} with the updated roles array. WordPress supports one primary role per user; sending multiple roles may result in only the last value being applied, depending on version and installed plugins. Note that WordPress uses POST - not PATCH or PUT - for updates to existing user records.
Deprovisioning: DELETE /wp-json/wp/v2/users/{id}?reassign={reassign_user_id}. The reassign parameter is mandatory; omitting it returns a 400 error. Deletion is permanent - WordPress core has no soft-delete or deactivation concept at the API layer. All Application Passwords issued to the deleted user are invalidated immediately, breaking any REST API or XML-RPC integrations that relied on those credentials.
Pagination uses offset-based paging via page and per_page parameters; default page size is 10, maximum is 100. The context query parameter (view, embed, edit) controls field visibility - edit context requires authentication and surfaces sensitive fields including email and capabilities.
Provision a new subscriber account
- Authenticate with Application Password credentials for an administrator account.
- POST /wp-json/wp/v2/users with body: {username, email, password, roles: ['subscriber']}.
- Capture the returned 'id' field for future reference.
- Optionally PATCH additional meta fields (first_name, last_name) via a follow-up POST /wp-json/wp/v2/users/{id}.
Watch out for: username is immutable after creation. Ensure the desired username is correct before submitting; there is no rename operation via the REST API.
Promote a user from subscriber to editor
- Authenticate as an administrator.
- GET /wp-json/wp/v2/users?slug={slug} to resolve the user's numeric ID.
- POST /wp-json/wp/v2/users/{id} with body: {roles: ['editor']}.
- Verify the response contains 'roles': ['editor'].
Watch out for: WordPress supports only one primary role per user. Sending multiple roles in the array may result in only the last role being applied depending on the WordPress version and any role-management plugins installed.
Deprovision (delete) a user and reassign their content
- Authenticate as an administrator.
- Identify the target user ID and the ID of the user who will receive reassigned content.
- DELETE /wp-json/wp/v2/users/{id}?reassign={reassign_user_id}.
- Confirm response contains 'deleted': true.
Watch out for: The 'reassign' parameter is mandatory. If the reassign target user ID does not exist or is invalid, the API returns a 400 error. There is no soft-delete or deactivation concept in WordPress core; deletion is permanent.
Why building this yourself is a trap
WordPress has no native SCIM 2.0 endpoint in core or on WordPress VIP. Any identity graph built on top of WordPress user data must be assembled through the REST API with administrator credentials, with no standardized provisioning protocol on the receiving end.
Plugin-based SCIM implementations exist but vary significantly in compliance, supported operations, and maintenance cadence - none are managed or guaranteed by Automattic.
Webhooks for user lifecycle events (creation, update, deletion) are also absent from core. Outbound notifications require either custom plugin code using WordPress action hooks (user_register, profile_update, delete_user) or a third-party automation plugin. This means any pipeline that needs to react to user changes in near-real-time must poll the API or maintain its own event infrastructure.
For teams building identity graph integrations - where WordPress user state needs to stay synchronized with a directory, IdP, or downstream SaaS - the absence of SCIM and native webhooks means the integration layer carries the full burden of consistency, error handling, and reconciliation.
Budget for that complexity explicitly before committing to a WordPress-native provisioning architecture.
Automate WordPress 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.