The WordPress REST API turns posts, media, users, custom content, and selected site operations into structured HTTP endpoints. That makes WordPress useful beyond a traditional theme, but the best projects start with a clear job instead of a vague plan to βgo headless.β
Here are five practical ways to use the API: accept a form from a separate frontend, power a mobile app, build a decoupled editor, synchronize a business system, and deliver webhooks. Each example includes the route shape, authentication choice, and failure cases that matter in production.
Start with the API contract
Core WordPress content is available under /wp-json/wp/v2/. A request to /wp-json/wp/v2/posts returns posts, while /wp-json/wp/v2/media returns media records. Plugins and custom code can add their own namespaces, such as /wp-json/acme/v1/.
Before writing a client, decide four things:
- Which system owns each field?
- Is the request public, user-authenticated, or server-to-server?
- Can the operation be repeated safely?
- What should happen when WordPress or the other system is unavailable?
Those questions prevent most integration problems. The endpoint itself is usually the easy part.
| Request type | Common authentication | Cache policy |
|---|---|---|
| Public content read | None | Cache by full URL and query string |
| Logged-in WordPress request | Cookie plus REST nonce | Do not share-cache |
| External trusted service | Application Password over HTTPS | Do not share-cache authenticated responses |
| Public form submission | Public custom route plus abuse controls | Never cache POST responses |
| Signed webhook | HMAC signature or provider signature | Never cache |
The official REST API authentication guide explains the core choices. Application Passwords are designed for API access, are stored hashed, and can be revoked independently. Give every integration its own low-privilege account and credential.
Authentication answers who is calling. Authorization still has to answer what that caller may do.
1. Accept a headless form submission
A marketing site built in Next.js, Astro, or another frontend can submit a contact or lead form to a custom WordPress endpoint. WordPress can validate the request, store a custom post, send a notification, or pass the record to a CRM.
Register a route such as:
POST /wp-json/acme/v1/leads
WordPress requires custom endpoints to be registered on rest_api_init. The custom endpoint guide recommends defining request arguments, validation, sanitization, and a permission_callback when calling register_rest_route().
A simplified route can look like this:
add_action( 'rest_api_init', function () {
register_rest_route( 'acme/v1', '/leads', [
'methods' => 'POST',
'permission_callback' => '__return_true',
'args' => [
'email' => [
'required' => true,
'sanitize_callback' => 'sanitize_email',
'validate_callback' => function ( $value ) {
return is_email( $value );
},
],
'message' => [
'required' => true,
'sanitize_callback' => 'sanitize_textarea_field',
],
],
'callback' => 'acme_create_lead',
] );
} );
A public permission_callback is reasonable for a public contact form, but it does not provide spam protection. Add rate limiting, a honeypot or challenge, request-size limits, and duplicate detection. Return 201 Created only after the record has actually been accepted.
Do not treat a WordPress nonce as a public anti-spam token. WordPress documents nonces as session-related request checks, not a substitute for authentication or authorization. A visitor who is not logged in needs a different abuse-control strategy.
Also exclude this route from CDN caching. A cached success response can expose submission details or make a failed replay look successful.
2. Power a mobile content app
A mobile app can use WordPress as a content backend for news, sermons, events, learning material, or a private member experience. Public content does not require authentication, so the first version can be simple.
A useful feed request is:
GET /wp-json/wp/v2/posts?per_page=20&_fields=id,slug,date_gmt,modified_gmt,title,excerpt,featured_media&_embed=wp:featuredmedia
The _fields parameter limits the response to what the screen needs. The global parameters guide explains that _fields can reduce response size and avoid work WordPress would otherwise perform. Use _embed selectively when the app needs related media in the same response.
For pagination, read X-WP-Total and X-WP-TotalPages from the response headers. WordPress caps per_page at 100, according to the official pagination documentation. Do not assume the first response contains the complete archive.
Cache public feed responses by the complete URL, including page, search term, category, locale, and every other query parameter. On the device, compare modified_gmt before replacing stored content.
If the app lets an authorized user create drafts or view private content, use a distinct Application Password for that app installation and store it in the operating systemβs secure credential store. Never ship a shared credential inside the app binary. Keep anonymous and authenticated caches separate, and delete protected cached content when the user logs out.
The core posts endpoint reference documents the fields and operations for reading, creating, and updating posts. The media endpoint reference covers attachment records and uploads.

One WordPress content source can serve several clients, but each client should request only the fields and permissions it needs.
3. Build a decoupled editorial interface
A custom editor is useful when contributors need a focused workflow instead of the full WordPress dashboard. A church volunteer might see only sermon title, speaker, date, campus, video URL, and notes. A product manager might edit a fixed set of catalog fields without seeing themes, plugins, or unrelated settings.
The workflow often uses these routes:
GET /wp-json/wp/v2/users/me?context=edit
GET /wp-json/wp/v2/posts/123?context=edit
POST /wp-json/wp/v2/posts/123
POST /wp-json/wp/v2/media
POST /wp-json/wp/v2/posts/123/autosaves
GET /wp-json/wp/v2/posts/123/revisions
Inside WordPress, cookie authentication plus an X-WP-Nonce created for wp_rest is the normal choice. Outside WordPress, use an Application Password over HTTPS, preferably through a trusted server component rather than exposing the credential to browser JavaScript.
A custom route should check a specific capability with current_user_can() inside permission_callback. Checking only whether a user is logged in is too broad. A subscriber and an editor are both authenticated, but they should not receive the same editing powers.
Treat edit responses as private. Never share-cache /users/me, drafts, revisions, autosaves, media uploads, or any request using context=edit. WordPress sends no-cache headers for authenticated REST requests, but a CDN configured to ignore Authorization or cookies can still create a serious leak.
The revisions and autosaves reference describes the supporting endpoints. A reliable editor should also handle 401, 403, and validation responses clearly instead of retrying the same request or silently dropping work.
For custom post types, register the type with show_in_rest => true. Register only the post meta fields the editor needs, provide schemas, and sanitize every write. The official guide to REST support for custom content types covers the registration options.
4. Synchronize WordPress with a CRM or catalog
A service business may need WordPress locations, staff profiles, or public inventory to stay aligned with a CRM. A store may need product changes to move between WooCommerce and an inventory platform. The REST API can support both patterns, but the source of truth must be explicit.
For a custom contact post type exposed to the API, an incremental pull might use:
GET /wp-json/wp/v2/contacts?modified_after=2026-09-19T10:00:00Z&orderby=modified&order=asc&per_page=100&_fields=id,modified_gmt,slug,meta
The integration should store a stable external ID in WordPress and upsert against it. A timeout after a successful write is common. If the retry creates a second record, the integration is not safe. Idempotent writes turn that retry into an update or a no-op.
Use an overlap window when polling by modification time. Then deduplicate by WordPress ID and modified_gmt. Without an overlap, records changed during pagination or sharing the same timestamp can be skipped. Process every page shown in X-WP-TotalPages.
For WooCommerce products, use its documented /wp-json/wc/v3/products routes and a REST API key restricted to the minimum required access. The official WooCommerce REST API documentation covers key creation and endpoint behavior.
Practical rules for a business-system sync:
- Expose only the meta fields the other system needs.
- Validate external IDs, prices, statuses, and enumerated values.
- Keep credentials in request headers, not query strings that may appear in logs.
- Record the last successful cursor and the last error.
- Separate customer data from public content caches.
- Purge or version API and frontend caches after a confirmed write.
- Build a reconciliation report for records that disagree.
WordPress object-cache invalidation does not automatically purge a CDNβs cached JSON. Treat API cache invalidation as an explicit part of the write workflow.
5. Send and receive reliable webhooks
Polling asks WordPress repeatedly whether anything changed. A webhook sends an event when the change happens. That is a better fit for publishing notifications, cache revalidation, search indexing, CRM updates, and automation workflows.
For outbound publishing events, WordPress provides hooks such as transition_post_status and save_post_{post_type}. The status-transition hook can run even when the old and new status are the same, so compare both values before sending a publish or unpublish event.
A production event should contain:
{
"event_id": "evt_01J...",
"event_type": "post.published",
"occurred_at": "2026-09-19T12:10:00Z",
"post_id": 123,
"post_type": "post",
"slug": "example-post"
}
Sign the raw request body with HMAC, include a timestamp, and send it over HTTPS. The receiver should verify the signature with a timing-safe comparison, reject stale timestamps, and retain processed event IDs so a retry cannot repeat the business action.
Use wp_remote_post() to deliver the request. If an administrator can configure the destination URL, prefer wp_safe_remote_post() because it validates the URL and redirects to reduce server-side request forgery risk.
Do not make an editor wait for a slow webhook destination. Queue the delivery, apply bounded retries with backoff, and log the final status. wp_schedule_single_event() can schedule retry work, but WP-Cron runs when traffic reaches the site after the scheduled time. Use a durable queue or real system scheduler when delivery timing is important.
For incoming webhooks, register a custom POST route and verify the provider signature before changing anything. A WordPress nonce is not server-to-server authentication. Never cache an incoming webhook response, and make the handler idempotent.

Webhooks are message delivery systems. Sign every message, expect retries, and make repeated delivery safe.
A production checklist
Before launching any of these projects, confirm that:
- Every custom route has an explicit
permission_callback. - Authorization checks a capability, not only login status.
- Inputs have schemas, validation, and sanitization.
- Credentials belong to dedicated low-privilege integration users.
- Browser and mobile code contain no shared server secrets.
- Public and authenticated responses use separate cache rules.
- Pagination processes every page.
- Writes are idempotent or have a documented duplicate-recovery path.
- Logs omit passwords, tokens, signatures, and unnecessary personal data.
- Timeouts, retries, and partial failures are visible to an operator.
- Webhook signatures and replay protection are tested.
- The integration can be disabled without taking down the public site.
The REST API works best as a narrow contract between systems. Start with one content type, one owner for each field, and one measurable workflow. Build the failure path before adding more endpoints. That approach produces an integration your team can operate, not just a demo that works once.