Developer docs

API reference

Endpoints for conversations, tags, and customers — plus the JSON object shapes they return.

All paths are relative to https://api.replyplex.com/public/v1. Mutating endpoints are marked (write) and need a write-scoped key.

A machine-readable OpenAPI spec is published at /public/v1/openapi.json, with an interactive viewer at /public/v1/docs — point your codegen/SDK tooling at it.

Conversations

List conversations

GET /conversations

Provide one of:

  • q — a search query (matches subject, customer, and message bodies; supports the same status: / assignee: / tag: operators as the console search). Not paginated, but limit is honoured (default 50, max 100), and inbox narrows the search to one mailbox. cursor and updatedAfter are rejected with a 400 rather than ignored.
  • inbox — an inbox id, paginated. Extra params: status=ACTIVE|PENDING|CLOSED|SNOOZED|SPAM, limit (default 50, max 100), updatedAfter (ISO-8601, incremental sync), and cursor.

The body is a plain array of conversation summaries, ordered newest-created first. When more pages exist, the response carries X-Next-Cursor (pass it back as cursor) and a GitHub-style Link: …; rel="next". Iterate until there’s no X-Next-Cursor; for incremental sync, pass the last timestamp you processed as updatedAfter.

# page 1 — read the cursor from the response headers
curl -si -H "Authorization: Bearer $RP_KEY" \
  "https://api.replyplex.com/public/v1/conversations?inbox=$INBOX&limit=50" | grep -i x-next-cursor
# page 2
curl -H "Authorization: Bearer $RP_KEY" \
  "https://api.replyplex.com/public/v1/conversations?inbox=$INBOX&cursor=$CURSOR"

Get one conversation

GET /conversations/:id

Returns a full conversation including messages, activity, and customFields.

Create a conversation (write)

POST /conversations

Body — an outbound message that starts a new ticket:

{
  "inboxId": "uuid",
  "to": "customer@example.com",
  "subject": "Welcome!",
  "bodyText": "Hi there…",
  "bodyHtml": "<p>Hi there…</p>",
  "cc": [],
  "bcc": [],
  "mode": "SEND",
  "attachments": []
}

mode is one of SEND, SEND_AND_PENDING, SEND_AND_CLOSE, SEND_AND_SNOOZE. Returns the created conversation. The inbox’s sending domain must be verified.

Reply to a conversation (write)

POST /conversations/:id/reply
{
  "bodyText": "Thanks for reaching out…",
  "bodyHtml": "<p>Thanks…</p>",
  "cc": [],
  "bcc": [],
  "mode": "SEND",
  "attachments": [],
  "scheduledFor": "2026-07-21T13:00:00.000Z",
  "savedReplyIds": []
}

Two optional fields:

  • scheduledFor — ISO 8601 datetime. When set, the reply is held instead of sent immediately (its message returns with deliveryState: "scheduled" and a scheduledFor timestamp) and dispatches at that time. Must be in the future, at most 30 days ahead. Composes with mode — a scheduled SEND_AND_CLOSE closes the conversation when the reply actually sends, not when you queue it.
  • savedReplyIds — up to 20 saved-reply UUIDs that were used composing this reply. Recorded on the reply_sent event and powers the analytics “Saved replies used” report. Insertion semantics: include a saved reply’s id even if the text was edited afterwards.

Add an internal note (write)

POST /conversations/:id/notes

Adds an internal note — no email is sent — and fires a message.created webhook with internalNote: true.

{
  "bodyText": "Called the customer — they'll send logs.",
  "mentions": []
}

Assign (write)

POST /conversations/:id/assign
{ "assigneeId": "uuid" }

Send "assigneeId": null to unassign.

Add / remove a tag (write)

POST   /conversations/:id/tags        { "tagId": "uuid" }
DELETE /conversations/:id/tags/:tagId

Close / reopen (write)

POST /conversations/:id/close
POST /conversations/:id/reopen

Update properties (write)

PATCH /conversations/:id

Set any subset of a conversation’s properties (at least one required). Omitted fields are left untouched; to unsnooze, call reopen.

{
  "priority": "HIGH",
  "snoozedUntil": "2026-08-01T09:00:00Z",
  "inboxId": "uuid",
  "customFields": [{ "fieldId": "uuid", "value": "Enterprise" }]
}
  • priorityLOW / NORMAL / HIGH / URGENT, or null to clear.
  • snoozedUntil — ISO 8601, must be in the future.
  • inboxId — move to another inbox.
  • customFields — set values by fieldId (value: null clears one).

All mutation endpoints return the updated conversation.

Tags

GET /tags

Returns the workspace’s tags.

Customers

GET /customers?q=<name-or-email>

Returns matching customers: an array of { "id", "name", "email" }.

Reference data

Read endpoints for resolving the ids the write endpoints need.

GET /inboxes                    # the org's live inboxes: { id, name, sendingDomainVerified }
GET /inboxes/:id/members        # assignable agents for an inbox (resolve assigneeId)
GET /saved-replies              # saved replies available to the key
GET /custom-fields              # custom-field definitions: { id, label, type, entity }

Join a conversation’s customFields[].fieldId to the definitions, and use an inbox id as the inbox / inboxId param when listing or creating.

Object shapes

Conversation summary

{
  "id": "uuid",
  "number": 1234,
  "inboxId": "uuid",
  "subject": "Refund not received",
  "status": "ACTIVE",
  "priority": "HIGH",
  "customerEmail": "a@b.com",
  "customerName": "James Carter",
  "assigneeId": "uuid | null",
  "assigneeName": "Emily Turner | null",
  "teamId": "uuid | null",
  "teamName": "Billing | null",
  "tags": ["Billing", "Bug"],
  "lastMessageAt": "2026-07-09T12:00:00.000Z | null",
  "preview": "…latest message excerpt…",
  "createdAt": "2026-07-01T…"
}

status is ACTIVE|PENDING|CLOSED|SNOOZED|SPAM; priority is LOW|NORMAL|HIGH|URGENT or null.

Conversation

The summary above plus:

{
  "tags": [ "…full Tag objects…" ],
  "following": false,
  "snoozedUntil": "… | null",
  "csatRating": "GOOD | NEUTRAL | BAD | null",
  "csatComment": "… | null",
  "messages": [ "…thread messages: direction, sender, to, cc, bodyText, bodyHtml, createdAt, attachments…" ],
  "activity": [ "…timeline events…" ],
  "customFields": [ { "fieldId": "uuid", "value": "…" } ]
}

Custom-field values are keyed by fieldId; the field’s label/type live in its definition (managed in Settings → Custom fields).

Tag

{ "id": "uuid", "name": "Billing", "type": "WORKFLOW", "color": "#F79009 | null" }