Skip to content
Gaurav TiwariDocs

REST API and Webhooks Reference

Updated October 18, 2026

You’re building a “What’s new” screen inside your plugin, a relay for your own mail server or a ticket form on a headless site. You need to know which routes exist, who may call them and what they return, and guessing from browser network logs is slow and fragile.

Core Support registers 29 routes under the core-support/v1 namespace, at https://desk.example.com/wp-json/core-support/v1/. Some are public, some need a key or a signature and some exist only for wp-admin screens. Each one is listed below with its access rule. Routes marked internal serve Core Support’s own screens and may change between releases, so I wouldn’t build on them.

How Access Works

  • Signed in: a WordPress user who belongs to this site, sent with WordPress’s cookie and a wp_rest nonce, or an application password.
  • Agent: a signed-in user with the core_support_work_tickets capability. Administrators, Support Agents and Support Managers have it.
  • Manager: a signed-in user with the core_support_manage capability. Administrators and Support Managers have it.
  • Mailbox token, relay secret, site key, portal session: the credentials described with each route.
  • Public: anyone, sometimes limited to a connected site’s listed addresses.

Ticket and mail routes answer 503 with storage_unavailable while the “Core Support setup failed” notice is showing. Most errors use WordPress’s usual JSON shape with code, message and data.status.

Tickets

These power the Customer Portal blocks and the agent workspace. Agents see every ticket; customers see only their own.

  • GET /tickets: signed in. Lists tickets, newest activity first. Parameters: status (open, waiting or resolved), search and page. Agents can also filter by assignment (mine or unassigned) and priority (normal, high or urgent).
  • POST /tickets: signed in. Opens a ticket with subject, body and an optional request_key. A repeat with the same key is stored once. Limited to 20 an hour per user.
  • GET /tickets/<id>: signed in. One ticket with its conversation. Private notes are left out for customers.
  • PATCH /tickets/<id>: signed in. Changes status, priority or assignee. Send the ticket’s current version; a stale version is refused, so 2 agents can’t overwrite each other. Customers can only change status, and only when the portal settings let them resolve or reopen.
  • POST /tickets/<id>/messages: signed in. Adds a reply with body, version, an optional request_key and visibility: public, or internal for agent notes. Limited to 120 an hour per user.
  • PATCH /tickets/<id>/deliveries/<delivery-id>: agents only. Sends action (retry or cancel) and the delivery’s current attempts. Retry works on a failed email, up to 5 attempts in all.
  • GET /tickets/<id>/attachments/<file-id>: signed in, with the same access as the conversation. Files always download. Add inline=1 to show PNG, JPEG, GIF, WebP or AVIF images in the browser.

An agent can send the header X-CS-View: customer to get exactly what the customer would see. Responses carry Cache-Control: private, no-store.

Incoming Mail Webhooks

The route key in these paths is site-<blog-id>-<mailbox-key>, such as site-1-support. Incoming mail → Connection details lists the exact URLs.

  • POST /webhooks/relay/<route-key>: relay secret. Receives raw email from the Cloudflare relay Worker. Body: the raw message, up to 3 MiB.
  • POST /webhooks/inbound/<route-key>: mailbox token. Receives email from FlowMattic, Zapier, Make, n8n or similar tools, as raw source or parsed JSON fields.
  • GET /webhooks/inbound/<route-key>: mailbox token. Tests the connection without sending anything. Returns ok, the mailbox address and max_bytes.

Send the token as Authorization: Bearer <token>, or as X-Core-Support-Token: <token> when your server strips the Authorization header. Send Email in from FlowMattic, Zapier, Make or n8n lists every JSON field.

Both POST routes answer:

  • 202: accepted. The body includes receipt_id.
  • 401: wrong token or signature.
  • 403: automation tools aren’t turned on for this mailbox.
  • 404: no mailbox uses this address. Stop retrying and check the URL.
  • 413: larger than the mailbox accepts.
  • 422: missing or invalid fields (inbound only). Retrying won’t help.
  • 503: temporarily unavailable. Retry later.

Relay Signature

The bundled Worker signs every request, and you only need this to write a relay of your own. Each request carries 3 headers:

  • X-Core-Support-Timestamp: Unix time in seconds. Requests more than 300 seconds off the server’s clock are refused.
  • X-Core-Support-Delivery: a unique ID for this delivery, 16 to 64 letters, digits or hyphens. A retry with the same ID is stored once.
  • X-Core-Support-Signature: v1= followed by a hex HMAC-SHA256.

The signed text is 5 lines joined with \n: v1, the route key, the timestamp, the delivery ID and the SHA-256 hex of the body. The HMAC key is the mailbox’s relay secret.

$payload   = implode("\n", ['v1', 'site-1-support', $timestamp, $delivery_id, hash('sha256', $raw_email)]);
$signature = 'v1=' . hash_hmac('sha256', $payload, $relay_secret);

Connected Sites

The site ID is the 12-character ID shown under Core Support → Connected sites.

  • POST /sites/<site-id>/tickets: a browser request from one of the site’s listed addresses, or a server request with the site key. Opens a ticket from email, name, subject, message and optional page_url. Browser requests are limited to 10 an hour per visitor address and 64 KiB each. Server requests send Authorization: Bearer <site key> (or X-Core-Support-Key), may add metadata and attachments, can be up to 8 MiB and always open a ticket directly.
  • GET /sites/<site-id>/portal/config: public, listed addresses only. The site name, whether new tickets are open, the message limit and hint and whether customers may resolve or reopen.
  • POST /sites/<site-id>/portal/code: public, listed addresses only. Emails a 6-digit sign-in code to email.
  • POST /sites/<site-id>/portal/session: public, listed addresses only. Exchanges email and code for a session token valid 30 days.
  • DELETE /sites/<site-id>/portal/session: portal session. Signs out.
  • GET /sites/<site-id>/portal/tickets: portal session. The customer’s tickets opened on that site.
  • POST /sites/<site-id>/portal/tickets: portal session. Opens a ticket with subject and message.
  • GET /sites/<site-id>/portal/tickets/<id>: portal session. One ticket and its public conversation.
  • PATCH /sites/<site-id>/portal/tickets/<id>: portal session. Resolves or reopens it with status and version, when your settings allow it.
  • POST /sites/<site-id>/portal/tickets/<id>/messages: portal session. Adds a reply with message and version.
  • GET /sites/<site-id>/portal/tickets/<id>/attachments/<file-id>: portal session. Downloads a file from that ticket.

Portal routes need Customer portal turned on for the site and answer 404 with portal_disabled otherwise. Send the session as Authorization: Bearer <session token> or X-CS-Portal. Host the Customer Portal on a Connected Site has the sign-in and rate limits.

Docs

  • GET /docs/search: public. Searches published docs with q (required), optional collection slug and site for an embedded site. Returns up to 8 results.
  • POST /docs/<id>/feedback: public. Records “Was this helpful?” with helpful (true or false) and an optional comment. One vote per doc, visitor and day, and 20 an hour per visitor.

Changelogs

  • GET /changelogs: public. Every product, with slug, name, type, url, latest, releases and feed.
  • GET /changelogs/<product>: public. A product’s releases, newest first, each with version, date, stability, url, summary, changes and html. Parameters: page, per_page (1 to 50, default 10), stable (true hides pre-releases) and since (only releases newer than that version).
  • POST /changelogs/admin/parse: internal, users who can edit docs. Reads changelog text into releases for the editor.
  • POST /changelogs/admin/probe: internal, users who can edit docs. Checks a sync source before saving it.
  • POST /changelogs/admin/<id>/sync: internal, users who can edit that changelog. Sync now on the edit screen.
curl 'https://desk.example.com/wp-json/core-support/v1/changelogs/my-plugin?since=1.1.0&stable=1'

Chat

The public Chat routes answer only for this site and the listed addresses of connected sites. New messages work only while Chat is turned on and the answer model’s provider has a key, and config reports that as enabled. Handoffs need Offer “Talk to a person” turned on. The message and handoff limits below are defaults that the core_support_chat_rate_limit filter can change.

  • GET /chat/config: public. The widget’s settings, wording and branding, including enabled and handoff.
  • POST /chat/messages: public. Sends message with the conversation’s thread and token, plus optional page_url and page_title. With stream set to true, the reply arrives as server-sent events. Limited to 20 a minute per conversation, 60 per 10 minutes per address and 240 a minute for the whole site.
  • GET /chat/threads/<uuid>: the conversation’s token in an X-Chat-Token header. Returns the conversation.
  • POST /chat/handoff: public. Turns a conversation into a ticket with thread, token, email and optional name and note. Limited to 5 an hour per address.
  • POST /chat/admin/test: internal, managers. Test connection on the Chat screen.
  • POST /chat/admin/learn: internal, managers. Learn all now, one batch at a time.
  • GET /chat/admin/learning: internal, agents. Learning progress for the Knowledge tab.

Team Alert Webhook

Webhooks also go the other way. The Webhook channel under Settings → Team alerts sends a JSON POST to your https:// URL for each new ticket and, if you turn it on, each customer reply.

{
  "event": "ticket_created",
  "title": "New ticket #42: License question",
  "url": "https://desk.example.com/wp-admin/admin.php?page=core-support&ticket=42",
  "ticket": {
    "id": 42,
    "subject": "License question",
    "status": "open",
    "priority": "normal",
    "source": "email",
    "customer_name": "Ada",
    "customer_email": "ada@example.net",
    "created_at": "2026-10-18 09:30:00",
    "message": ""
  },
  "sent_at": "2026-10-18T09:30:02+00:00"
}
  • event is ticket_created, customer_replied or test.
  • The X-Core-Support-Event header repeats the event.
  • ticket.message is filled only when Include a message preview is on.
  • With a signing secret, X-Core-Support-Signature is sha256= followed by the HMAC-SHA256 of the raw body.

Rate limits, server errors and timeouts are retried after 1, 5 and 30 minutes. Team Alerts on Telegram, Pushover, Discord, Slack or a Webhook covers the channel settings.

Share

Was this helpful?

Still stuck? Open a support ticket