A CMS API is a contract between a content system and its consumers. A mobile app, a storefront and an editorial tool may all need the same article, but they should not necessarily see or change the same fields. The hard part is not producing JSON; it is defining permissions, change behavior and recovery when the network fails.

The examples below describe an imaginary service. Check the documentation for your own CMS before using its routes or authorization mechanism.

Model the resources before choosing endpoints

Start with the business flow: who creates an article, who may publish it, which service owns its title, and whether a consumer needs drafts or only published content. Resolve conflicting ownership explicitly. If a catalog price can be edited both in the CMS and in an inventory system, decide which update wins before synchronizing either direction.

A typical resource-oriented API might expose these operations:

  • GET /api/v1/articles lists articles visible to the caller.
  • GET /api/v1/articles/42 retrieves a single permitted article.
  • POST /api/v1/articles creates an article.
  • PUT /api/v1/articles/42 sends a replacement representation as defined by the contract.
  • PATCH /api/v1/articles/42 applies a supported partial update.
  • DELETE /api/v1/articles/42 requests deletion; a product may document an archival behavior.

The resource names are examples, not universal CMS routes. JSON is a common representation, but JSON alone does not make an API RESTful. REST is an architectural style with constraints, including a uniform interface and stateless requests.

An example response might look like this:

HTTP/1.1 200 OK Content-Type: application/json { "id": 42, "title": "Choosing a CMS", "status": "published", "updated_at": "2026-10-20T12:00:00Z" } 

Document data types, optional fields, timestamps, pagination and error bodies. Do not assume all callers may see every field. Consumers rendering content must still handle HTML and links safely.

Separate identity from permission

Authentication establishes the identity of a caller; authorization decides what that caller may do. A public reader might access published articles, an author may edit their own drafts, and a storefront integration may need read-only access to selected product fields.

Enforce those rules on the server for every request and object. Hiding an edit button in a browser does not secure an endpoint. An attacker guessing a sequential article ID must not be able to read someone else's draft.

For server-to-server work, use a dedicated identity with the smallest useful permissions. If the service supports bearer tokens, send them over HTTPS in the Authorization header rather than a query string, where they may leak through logs or history. Set up secure storage, rotation and revocation. OAuth 2.0 can provide delegated authorization when the service supports it; the available flows depend on the provider.

Never embed an administrator secret in browser JavaScript or a mobile app. Use a supported public-client flow or a controlled server-side intermediary, and authorize requests at that intermediary too. Browser sessions based on cookies also need appropriate CSRF protection. CORS is a browser access policy, not an authorization system.

Treat status codes as part of the contract

A successful read commonly returns 200, while successful creation may return 201 and an operation without a response body may return 204. Invalid input can produce 400 or 422, depending on the API.

Useful failures include:

  • 401 when acceptable authentication credentials are missing or rejected.
  • 403 when access is forbidden; some services return 404 to avoid revealing a resource.
  • 409 for a conflict with the current state.
  • 412 when a request precondition such as If-Match fails.
  • 429 for rate limiting; honor Retry-After when supplied.

A client should show a helpful error without exposing access tokens or internal stack traces. Log enough context to diagnose the problem, but redact credentials and avoid collecting unnecessary personal data.

Design retries around the method

A timeout does not prove a write failed: the server may have saved the article before the response was lost. An unconditional repeat of a POST can therefore create duplicates.

HTTP defines the intended effect of repeated PUT and DELETE requests as idempotent, although individual responses may differ. Do not assume that a particular PATCH or POST is safe to repeat. If the service explicitly supports idempotency keys, use them as documented. Otherwise reconcile the operation by a stable external identifier or operation record before creating another resource.

Avoid lost editorial changes

Imagine two editors opening the same draft. One corrects the headline while the other updates the introduction. If both submit the entire old representation, the last save can silently erase the first.

Optimistic concurrency makes the conflict visible. One common implementation returns a strong ETag when reading an article; the client supplies it in If-Match when saving. If the resource has changed, a supporting server can reject the update with 412. The client then reloads the current content and lets the editor reconcile the changes. Other APIs use their own revision field instead, so check the documented mechanism.

Publishing is also a distinct permission. Decide whether authors can create drafts, whether editors approve them, and which API operation makes content public. Apply the same access rules to attachments and linked data.

Synchronize collections safely

Large catalogs should be read in pages. Offset pagination is straightforward for page navigation, but inserts and deletions between requests can shift rows and cause omissions or duplicates. Cursor pagination with a stable ordering can be a better fit for changing collections, provided the server documents its guarantees.

For incremental sync, verify how the API handles equal timestamps, time zones and deleted resources. Save a checkpoint after a page has been processed successfully. Make processing repeatable by recording stable IDs and handling a previously seen item safely. If webhooks are available, verify their authenticity and tolerate duplicate delivery; periodic reconciliation can still be necessary.

Plan for compatibility

Versioning can appear in a path such as /v1/, a header or another documented mechanism. REST does not require a version number in the URL. Whatever scheme you choose, explain the support period and deprecation process.

Removing a field, changing an identifier's type or redefining a status can break consumers. An optional new field is often easier to introduce, but a strict client can still reject it. Test real consumers, publish a changelog and give them time to migrate incompatible changes.

A practical integration checklist

  1. Identify the source of truth for each field and the permitted data flow.
  2. Read the real API contract: routes, authentication, errors, pagination and limits.
  3. Create a separate integration identity with minimal permissions.
  4. Test reads and writes in an authorized environment, including hidden drafts and attachments.
  5. Simulate timeouts after writes, duplicate events, stale revisions and rate limits.
  6. Monitor failures without logging secrets, and assign an owner for credential rotation and upgrades.

A robust CMS integration is one that behaves predictably when everything is working and when it is not. Make the permissions, data contract and recovery path explicit before connecting production systems.

Russian original: https://morlix.ru/blog/rest-api-dlya-cms-marshruty-avtorizatsiya-i-versii

Original article (Russian)