Skip to content
Esc
  • OverviewGuidesWhat exists today, and where to start.
  • QuickstartGuidesKey, domain, first send — in that order.
  • AuthenticationGuidesBearer keys, the mandatory User-Agent, and what each refusal means.
  • ErrorsGuidesThe whole vocabulary, with the status each name carries.
  • IdempotencyGuidesRetry a send without sending it twice.
  • PaginationGuidesCursors are item IDs, not page numbers.
  • Rate limitsGuidesTen a second per team, and the headers that tell you where you are.
  • EventsGuidesEvery event a webhook can carry, with one real payload each.
  • DomainsGuidesThe records, where they go at each registrar, and what the page does while you wait.
  • TrackingGuidesOpens and clicks: one record, two toggles, and what an open really means.
  • TemplatesGuidesFifty-seven starters sorted by goal, and how to keep a campaign as a template.
  • ReceivingGuidesInbound mail, and the Inbox: a webhook fires, you read it, you answer it.
  • InboxGuidesChannels, personal mailboxes and seats: who sees what, and where a reply goes.
  • Mail appsGuidesComing soon: your Rasket address in Apple Mail, Outlook and the Gmail app.
  • Inbox APIGuidesOpen, read and answer support conversations from your app, with the same key.
  • Support inbox in your appGuidesA Contact us form that opens a conversation your team answers, in five minutes.
  • Replies to your emailsGuidesOne field on a send, and the customer's reply opens a conversation.
  • Let an agent triageGuidesAn AI agent reads, notes and drafts over MCP; a person sends.
  • Node SDKGuidesThe rasket package: typed from the API's own document, retries only what is safe.
  • Python SDKGuidesThe rasket package on PyPI: the Node client's methods, in snake_case, over httpx.
  • MCP serverGuidesConnect Claude, ChatGPT or any MCP client: your scopes, no key.
  • AI assistGuidesSubject lines, drafts and diagnosis — in the dashboard and over the API, off until you allow it.
  • AgentsGuidesLet an AI agent set Rasket up: the skill, the rules file, MCP, and the recipe they share.
  • OAuthGuidesLet another app act for a team: register, authorize with PKCE, exchange, refresh.
  • Single sign-onGuidesOIDC login for your team, a domain proved by DNS, enforcement and break-glass.
  • IntegrationsGuidesVercel, Netlify and Cloudflare, Zapier and n8n, a WordPress plugin, and Notion contacts.
  • SMTPGuidesSend from anything that speaks SMTP: settings, setup guides, limits and replies.
  • ZapierGuidesSend email, add contacts and react to email events from a Zap, with no code.
  • n8nGuidesThe Rasket node and trigger for n8n workflows: install, connect, every operation.
  • VercelGuidesAdd Rasket on Vercel: a Sending key in each project as RASKET_API_KEY, no copying.
  • WordPressGuidesThe Rasket plugin: every email your site sends, through Rasket, with a safe fallback.
  • NotionGuidesTurn a Notion database of people into contacts in a segment, once or every hour.
  • Migrating to RasketGuidesBring contacts, unsubscribes, lists and templates from Mailchimp, Klaviyo and more.
  • EmailsAPI referenceSend, batch, retrieve, list, reschedule, cancel, attachments.
  • DomainsAPI referenceAdd a domain, publish its records, verify it.
  • API keysAPI referenceCreate, list, rename and revoke credentials.
  • WebhooksAPI referencePayloads, signature verification, retries and replay.
  • SuppressionsAPI referenceAddresses we will not send to, and why.
  • LogsAPI referenceEvery request made with this team's credentials.
  • MetricsAPI referenceDelivery, bounce, complaint and engagement counts.
  • TemplatesAPI referenceVersioned email content with typed variables, addressed by ID or alias.
  • ContactsAPI referenceYour audience: contacts, their typed properties, segments and topic choices.
  • SegmentsAPI referenceAudiences defined by a filter, by hand, or both.
  • TopicsAPI referenceWhat contacts subscribe to, and the preference page's list.
  • CampaignsAPI referenceCampaigns, at /broadcasts: one message to a segment, from draft to results.
  • ImportsAPI referenceCSV uploads: column mapping, conflicts and counts.
  • AutomationsAPI referenceWorkflows that run per contact: the graph, its versions, and every run.
  • Custom eventsAPI referenceThe names your product fires, and what starts a workflow.
  • ReceivingAPI referenceMail sent to you: the message, its attachments, its raw source.
  • OAuthAPI referenceClient registration, the token endpoint, and the grants a team has given.
  • TeamAPI referenceThe team a credential belongs to: its plan, sender identity, AI flag and members.
  • BillingAPI referencePlan, usage, invoices and add-ons, and the hosted pages where a customer pays.
  • AI helpersAPI referenceSubject lines, a first draft, and why an email did what it did.
  • InboxAPI referenceChannels, conversations, messages, notes and search in your support inbox.

API referenceInbox

Inbox

Your team's support conversations: open them from your app, read and search them, reply from the channel's address, and keep internal notes. Start with the Inbox API guide if this is your first call.

Shared channels only

Every call reaches conversations in your team's open shared channels, such as support@. A personal mailbox belongs to its person: no key, token or agent can reach it, and its conversation IDs answer 404, the same as an ID that does not exist.

Inbox access

A key's Inbox access is set apart from its permission, and every key starts at none — a Full access key included. A team admin raises it in the dashboard under API keys, and can limit the key to some channels. A restricted channel is reachable only by a key limited to it.

Inbox access levels
inbox_accessCan
noneThe default, on every key. The key cannot reach the Inbox.
createOpen conversations only: POST /inbox/conversations and nothing else.
readList, read and search conversations, messages and notes.
writeRead and reply: also reply, add notes, assign, and set status, labels and folders.

An OAuth token needs inbox:read for reads and inbox:write for writes; one does not imply the other.

A key is your app, not a person

  • A reply from a key goes out from the channel's own name and address. A note from a key shows the key's name, and keeps it after the key is revoked.
  • Read marks, stars, snoozes and drafts are one person's, so a key has none. Every list shows the team's view.
  • A token or a session acts as its member, with that member's channels and role. A viewer reads and cannot write.

/inbox request and response bodies are not kept in your request logs, because they hold your customers' mail. The method, path, status and timing are.

Refusals worth knowing

Inbox refusals
StatusMeans
403 inbox_not_set_upYour project has no open channel yet. Create one in Rasket Inbox.
403 invalid_permissionThe key has no Inbox access, or not enough for this call; or the token lacks the scope.
404 not_foundNo such channel or conversation, or one this credential cannot reach — a personal mailbox included.
409 conversation_conflictA teammate is replying, a newer message arrived, or the conversation is in Spam or the Trash.
412 precondition_failedThe If-Match version is no longer current.
422 snooze_needs_a_personAn API key tried to snooze. Use status pending.

The whole vocabulary is on Errors. Inbox webhook events are on Events.

Endpoints

List Inbox channels

GET /inbox/channels

The shared channels this credential can reach, with their addresses.

Request

curl -X GET "https://api.rasket.com/inbox/channels" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "list",
  "has_more": false,
  "data": [
    {
      "object": "inbox_channel",
      "id": "0192f6a8-3c1e-7a40-9b2d-5e8f1a6c4d20",
      "address": "support@lumen.app",
      "name": "Lumen Support",
      "restricted": false
    }
  ]
}
  • Personal mailboxes are never listed. A restricted channel is listed only for a key limited to it.
  • A project with no open channel answers 403 inbox_not_set_up on every /inbox route.

List who can be assigned in a channel

GET /inbox/channels/{channel_id}/teammates

The teammates who can open this channel, by name.

Path parameters

  • channel_idstringRequired

    The channel's ID, from GET /inbox/channels.

Request

curl -X GET "https://api.rasket.com/inbox/channels/0192f6a8-3c1e-7a40-9b2d-5e8f1a6c4d20/teammates" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "list",
  "has_more": false,
  "data": [
    {
      "object": "inbox_teammate",
      "user_id": "0192a001-5b6c-7d8e-9f01-23456789abcd",
      "name": "Dana Ortiz",
      "can_write": true
    }
  ]
}
  • can_write is false for a viewer, who reads the channel and cannot be assigned. Teammates are named, never addressed.

List labels

GET /inbox/labels

The team's labels. A person's own labels are never listed.

Request

curl -X GET "https://api.rasket.com/inbox/labels" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "list",
  "has_more": false,
  "data": [
    {
      "object": "inbox_label",
      "id": "0192f6b2-1d4e-7f60-8a9b-0c1d2e3f4a5b",
      "name": "Billing",
      "colour": "blue",
      "channel_id": null
    }
  ]
}

List folders

GET /inbox/folders

The team's folders. A person's own folders are never listed.

Request

curl -X GET "https://api.rasket.com/inbox/folders" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "list",
  "has_more": false,
  "data": [
    {
      "object": "inbox_folder",
      "id": "0192f6b3-2e5f-7a71-9bac-1d2e3f4a5b6c",
      "name": "Refunds",
      "parent_id": null,
      "channel_id": "0192f6a8-3c1e-7a40-9b2d-5e8f1a6c4d20"
    }
  ]
}

List conversations

GET /inbox/conversations

Conversations in the channels you can reach, newest first.

Query parameters

  • limitinteger

    How many items to return, 1–100. Defaults to 20.

  • afterstring

    Return the page that follows this item ID. Mutually exclusive with before.

  • beforestring

    Return the page that precedes this item ID. Mutually exclusive with after.

  • channel_idstring

    Only conversations in this channel.

  • statusstring

    open, pending or done.

  • assignee_idstring

    Only conversations assigned to this teammate, or none for unassigned ones.

  • external_idstring

    The conversation your app opened with this external_id.

3 more fields (label_id, folder_id, place)
  • label_idstring

    Only conversations carrying this team label.

  • folder_idstring

    Only conversations filed in this team folder.

  • placestring

    inbox (the default; includes conversations filed in a folder), archive, spam or trash. With external_id and no place, every place is searched.

Request

curl -X GET "https://api.rasket.com/inbox/conversations?status=open&limit=20" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "list",
  "has_more": false,
  "data": [
    {
      "object": "inbox_conversation",
      "id": "0192f8e1-7a40-7c55-b1e3-0f0a3b6d2e91",
      "channel": {
        "id": "0192f6a8-3c1e-7a40-9b2d-5e8f1a6c4d20",
        "address": "support@lumen.app"
      },
      "subject": "Can I move my plan to annual?",
      "status": "open",
      "assignee": null,
      "labels": [
        {
          "id": "0192f6b2-1d4e-7f60-8a9b-0c1d2e3f4a5b",
          "name": "Billing",
          "colour": "blue"
        }
      ],
      "place": "inbox",
      "folder_id": null,
      "origin": "app",
      "external_id": "ticket_58213",
      "metadata": {
        "user_id": "usr_8412",
        "plan": "Team"
      },
      "customer": {
        "email": "priya@harborcoffee.co",
        "name": "Priya Raman",
        "contact_id": null,
        "recent_emails": null
      },
      "latest_from": "Priya Raman <priya@harborcoffee.co>",
      "snippet": "Hi! We love Lumen. Can we switch to yearly billing?",
      "message_count": 1,
      "last_message_at": "2026-10-04T09:03:12.000Z",
      "last_inbound_at": "2026-10-04T09:03:12.000Z",
      "created_at": "2026-10-04T09:03:12.000Z",
      "updated_at": "2026-10-04T09:03:12.000Z"
    }
  ]
}
  • Filters combine. A row has no messages; retrieve the conversation for those.
  • Every list shows the team's view: no read marks, stars or snoozes, which are one person's.

Create a conversation

POST /inbox/conversations

Open a conversation from your app, such as a Contact us form.

Headers

  • Idempotency-Keystring

    1–256 characters, unique to this send. Replaying it inside 24 hours returns the original response instead of sending again.

Body

  • channelstringRequired

    A channel ID, or its full address such as support@lumen.app.

  • fromobjectRequired

    { email, name }: the customer. Replies go to this address. Rasket does not check it, and the conversation says so.

  • subjectstringRequired

    One line, up to 998 characters.

  • textstring

    The message. Send text, html or both; up to 256 KB together.

  • htmlstring

    The message as HTML.

  • external_idstring

    Your own ID for this conversation, unique in your project. Sending one that already exists adds this message to that conversation and reopens it. Nothing else joins two messages from your app: not the sender, not the subject.

  • metadataobject

    Up to 20 keys, each value a string of up to 500 characters. Shown to your team beside the conversation; replaced when you send it again.

1 more field (attachments)
  • attachmentsobject[]

    Up to 10 files, 10 MB in total, each { filename, content, content_type } with content base64-encoded. A URL is never fetched.

Request

curl -X POST "https://api.rasket.com/inbox/conversations" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: contact-58213" \
  -d '{
  "channel": "support@lumen.app",
  "from": {
    "email": "priya@harborcoffee.co",
    "name": "Priya Raman"
  },
  "subject": "Can I move my plan to annual?",
  "text": "Hi! We love Lumen. Can we switch to yearly billing?",
  "external_id": "ticket_58213",
  "metadata": {
    "user_id": "usr_8412",
    "plan": "Team"
  }
}'

Response 201

{
  "object": "inbox_conversation",
  "id": "0192f8e1-7a40-7c55-b1e3-0f0a3b6d2e91",
  "channel": {
    "id": "0192f6a8-3c1e-7a40-9b2d-5e8f1a6c4d20",
    "address": "support@lumen.app"
  },
  "status": "open",
  "origin": "app",
  "external_id": "ticket_58213",
  "message_id": "0192f8e1-7a52-7d10-8c44-91a0b2c3d4e5",
  "created": true
}
  • 201 opens a conversation. 200 with created: false means external_id named one that exists, and the message was added to it.
  • Needs Inbox access create (Open conversations only) or write (Read and reply), or inbox:write on a token.
  • An unknown channel, or one the key may not use, is 404; personal mailboxes never are usable. An external_id that belongs to another channel is 422.
  • It is received mail, and free. It never appears on /emails/receiving and fires no email.received; it fires inbox.conversation.created (or inbox.message.received on an append).
  • Each credential may open 500 conversations or messages an hour; past that it is 429.

Retrieve a conversation

GET /inbox/conversations/{conversation_id}

One conversation, its newest messages and the customer.

Path parameters

  • conversation_idstringRequired

    The conversation's ID.

Request

curl -X GET "https://api.rasket.com/inbox/conversations/0192f8e1-7a40-7c55-b1e3-0f0a3b6d2e91" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "inbox_conversation",
  "id": "0192f8e1-7a40-7c55-b1e3-0f0a3b6d2e91",
  "channel": {
    "id": "0192f6a8-3c1e-7a40-9b2d-5e8f1a6c4d20",
    "address": "support@lumen.app"
  },
  "subject": "Can I move my plan to annual?",
  "status": "open",
  "assignee": null,
  "labels": [
    {
      "id": "0192f6b2-1d4e-7f60-8a9b-0c1d2e3f4a5b",
      "name": "Billing",
      "colour": "blue"
    }
  ],
  "place": "inbox",
  "folder_id": null,
  "origin": "app",
  "external_id": "ticket_58213",
  "metadata": {
    "user_id": "usr_8412",
    "plan": "Team"
  },
  "customer": {
    "email": "priya@harborcoffee.co",
    "name": "Priya Raman",
    "contact_id": null,
    "recent_emails": null
  },
  "latest_from": "Priya Raman <priya@harborcoffee.co>",
  "snippet": "Hi! We love Lumen. Can we switch to yearly billing?",
  "message_count": 1,
  "last_message_at": "2026-10-04T09:03:12.000Z",
  "last_inbound_at": "2026-10-04T09:03:12.000Z",
  "created_at": "2026-10-04T09:03:12.000Z",
  "updated_at": "2026-10-04T09:03:12.000Z",
  "messages": [
    {
      "object": "inbox_message",
      "id": "0192f8e1-7a52-7d10-8c44-91a0b2c3d4e5",
      "direction": "inbound",
      "from": "Priya Raman <priya@harborcoffee.co>",
      "to": ["support@lumen.app"],
      "cc": [],
      "subject": "Can I move my plan to annual?",
      "occurred_at": "2026-10-04T09:03:12.000Z",
      "text": "Hi! We love Lumen. Can we switch to yearly billing?",
      "html": null,
      "body_unavailable": false,
      "attachments": [],
      "received_email_id": "0192f8e1-7a4f-7b20-a1c3-6d5e4f3a2b10",
      "email_id": null,
      "dropped_reason": null,
      "sent_by": null
    }
  ]
}
  • The response carries an ETag. Send it back as If-Match on an update to refuse a stale write.
  • customer.recent_emails lists the last 10 emails you sent to the customer, only for a credential that can also read sent email (a Full access key, or emails:read on a token). Otherwise it is null.
  • A conversation in a personal mailbox answers 404, the same as one that does not exist.

Update a conversation

PATCH /inbox/conversations/{conversation_id}

Set the status, assign it, change labels, or file it.

Path parameters

  • conversation_idstringRequired

    The conversation's ID.

Headers

  • If-Matchstring

    The ETag from a read or an earlier update. A stale one is 412 precondition_failed; * or none skips the check.

Body

  • statusstring

    open, pending or done.

  • assignee_idstring | null

    A teammate who can open the channel and write, or null for nobody.

  • labelsobject

    { add, remove }: team label IDs, up to 50 each.

  • folder_idstring | null

    A team folder to file it in, or null to take it back to the Inbox.

1 more field (snooze_until)
  • snooze_untilstring | null

    A token's or session's own snooze. A snooze is a person's: an API key gets 422 snooze_needs_a_person. Use status pending instead.

Request

curl -X PATCH "https://api.rasket.com/inbox/conversations/0192f8e1-7a40-7c55-b1e3-0f0a3b6d2e91" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "pending",
  "assignee_id": "0192a001-5b6c-7d8e-9f01-23456789abcd",
  "labels": {
    "add": ["0192f6b2-1d4e-7f60-8a9b-0c1d2e3f4a5b"]
  }
}'

Response 200

{
  "object": "inbox_conversation",
  "id": "0192f8e1-7a40-7c55-b1e3-0f0a3b6d2e91",
  "channel": {
    "id": "0192f6a8-3c1e-7a40-9b2d-5e8f1a6c4d20",
    "address": "support@lumen.app"
  },
  "subject": "Can I move my plan to annual?",
  "status": "pending",
  "assignee": null,
  "labels": [
    {
      "id": "0192f6b2-1d4e-7f60-8a9b-0c1d2e3f4a5b",
      "name": "Billing",
      "colour": "blue"
    }
  ],
  "place": "inbox",
  "folder_id": null,
  "origin": "app",
  "external_id": "ticket_58213",
  "metadata": {
    "user_id": "usr_8412",
    "plan": "Team"
  },
  "customer": {
    "email": "priya@harborcoffee.co",
    "name": "Priya Raman",
    "contact_id": null,
    "recent_emails": null
  },
  "latest_from": "Priya Raman <priya@harborcoffee.co>",
  "snippet": "Hi! We love Lumen. Can we switch to yearly billing?",
  "message_count": 1,
  "last_message_at": "2026-10-04T09:03:12.000Z",
  "last_inbound_at": "2026-10-04T09:03:12.000Z",
  "created_at": "2026-10-04T09:03:12.000Z",
  "updated_at": "2026-10-04T09:41:55.000Z"
}
  • Needs Inbox access write (Read and reply), or inbox:write on a token.
  • Every check runs before any write, so a refused update changes nothing.
  • A conversation in Spam or the Trash is 409; archive and trash are not set through the API.

Reply to a conversation

POST /inbox/conversations/{conversation_id}/reply

Send a reply from the channel's own address.

Path parameters

  • conversation_idstringRequired

    The conversation's ID.

Headers

  • Idempotency-Keystring

    1–256 characters, unique to this send. Replaying it inside 24 hours returns the original response instead of sending again.

Body

  • textstringRequired

    The reply.

  • htmlstring

    The reply as HTML.

  • statusstring

    Set the status once the reply has gone, such as pending.

  • latest_message_idstring

    The newest message you have read. If a newer one has arrived, the reply is 409 conversation_conflict naming it.

7 more fields (from, cc, bcc, subject, attachments, reply_to_message_id, force)
  • fromstring

    The channel's address or one of its aliases. Defaults to the address the message arrived at.

  • ccstring[]

    Visible copies.

  • bccstring[]

    Blind copies.

  • subjectstring

    Re: <the original> when absent.

  • attachmentsobject[]

    { filename, content_type, content }, base64 only. The same limits as POST /emails.

  • reply_to_message_idstring

    The customer's message being answered; the newest one when absent.

  • forceboolean

    Send even though a teammate is replying in Rasket Inbox right now.

Request

curl -X POST "https://api.rasket.com/inbox/conversations/0192f8e1-7a40-7c55-b1e3-0f0a3b6d2e91/reply" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: reply-58213-1" \
  -d '{
  "text": "Hi Priya — yes, we can switch you to annual. It starts on your next bill.",
  "status": "pending"
}'

Response 201

{
  "object": "inbox_reply",
  "conversation_id": "0192f8e1-7a40-7c55-b1e3-0f0a3b6d2e91",
  "message_id": "0192f8e3-4c5d-7e6f-8a9b-0c1d2e3f4a5b",
  "email_id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
  "from": "Lumen Support <support@lumen.app>",
  "to": ["priya@harborcoffee.co"],
  "cc": [],
  "subject": "Re: Can I move my plan to annual?",
  "status": "pending",
  "suppressed": false
}
  • Needs Inbox access write (Read and reply), or inbox:write on a token.
  • A reply is a send: it counts on your plan's sending quota like any other email, and appears on /emails under email_id.
  • A teammate replying in Rasket Inbox right now is 409 conversation_conflict unless you send force: true. Spam and the Trash are 409 too.
  • Each key may send 60 replies an hour, on top of the team's own sending limits.

List a conversation's messages

GET /inbox/conversations/{conversation_id}/messages

Every message, oldest first, with its body.

Path parameters

  • conversation_idstringRequired

    The conversation's ID.

Query parameters

  • limitinteger

    1–20, default 10. Each message carries its body.

  • afterstring

    Return the page that follows this item ID. Mutually exclusive with before.

  • beforestring

    Return the page that precedes this item ID. Mutually exclusive with after.

Request

curl -X GET "https://api.rasket.com/inbox/conversations/0192f8e1-7a40-7c55-b1e3-0f0a3b6d2e91/messages" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "list",
  "has_more": false,
  "data": [
    {
      "object": "inbox_message",
      "id": "0192f8e1-7a52-7d10-8c44-91a0b2c3d4e5",
      "direction": "inbound",
      "from": "Priya Raman <priya@harborcoffee.co>",
      "to": ["support@lumen.app"],
      "cc": [],
      "subject": "Can I move my plan to annual?",
      "occurred_at": "2026-10-04T09:03:12.000Z",
      "text": "Hi! We love Lumen. Can we switch to yearly billing?",
      "html": null,
      "body_unavailable": false,
      "attachments": [],
      "received_email_id": "0192f8e1-7a4f-7b20-a1c3-6d5e4f3a2b10",
      "email_id": null,
      "dropped_reason": null,
      "sent_by": null
    }
  ]
}
  • body_unavailable: true means the body could not be read just now, or is no longer kept. The message is still there.
  • sent_by names the teammate or API key that sent an outbound message.

List a conversation's internal notes

GET /inbox/conversations/{conversation_id}/notes

Notes your team left. Never sent to the customer.

Path parameters

  • conversation_idstringRequired

    The conversation's ID.

Query parameters

  • limitinteger

    How many items to return, 1–100. Defaults to 20.

  • afterstring

    Return the page that follows this item ID. Mutually exclusive with before.

  • beforestring

    Return the page that precedes this item ID. Mutually exclusive with after.

Request

curl -X GET "https://api.rasket.com/inbox/conversations/0192f8e1-7a40-7c55-b1e3-0f0a3b6d2e91/notes" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "list",
  "has_more": false,
  "data": [
    {
      "object": "inbox_note",
      "id": "0192f8e2-0b1c-7d2e-8f3a-4b5c6d7e8f90",
      "body": "Customer since 2024, on the Team plan. Offer the annual discount.",
      "author": {
        "type": "api_key",
        "api_key_id": "a4d2f0c8-5b31-4e7a-9c62-8f0b1d4e6a75",
        "name": "Lumen web app",
        "revoked": false
      },
      "created_at": "2026-10-04T09:41:55.000Z"
    }
  ]
}

Add an internal note

POST /inbox/conversations/{conversation_id}/notes

A note for your team, written by this key.

Path parameters

  • conversation_idstringRequired

    The conversation's ID.

Headers

  • Idempotency-Keystring

    1–256 characters, unique to this send. Replaying it inside 24 hours returns the original response instead of sending again.

Body

  • bodystringRequired

    Plain text, up to 10,000 characters.

  • mentioned_user_idsstring[]

    Teammates to tell by email, from GET /inbox/channels/{channel_id}/teammates. Up to 10.

Request

curl -X POST "https://api.rasket.com/inbox/conversations/0192f8e1-7a40-7c55-b1e3-0f0a3b6d2e91/notes" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0" \
  -H "Content-Type: application/json" \
  -d '{
  "body": "Customer since 2024, on the Team plan. Offer the annual discount."
}'

Response 201

{
  "object": "inbox_note",
  "id": "0192f8e2-0b1c-7d2e-8f3a-4b5c6d7e8f90",
  "body": "Customer since 2024, on the Team plan. Offer the annual discount.",
  "author": {
    "type": "api_key",
    "api_key_id": "a4d2f0c8-5b31-4e7a-9c62-8f0b1d4e6a75",
    "name": "Lumen web app",
    "revoked": false
  },
  "created_at": "2026-10-04T09:41:55.000Z"
}
  • Needs Inbox access write (Read and reply), or inbox:write on a token. A note by a key shows the key's name, kept even after the key is revoked.

Mark a conversation read

POST /inbox/conversations/{conversation_id}/read

Mark it read for the person behind a token.

Path parameters

  • conversation_idstringRequired

    The conversation's ID.

Request

curl -X POST "https://api.rasket.com/inbox/conversations/0192f8e1-7a40-7c55-b1e3-0f0a3b6d2e91/read" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "inbox_read_mark",
  "conversation_id": "0192f8e1-7a40-7c55-b1e3-0f0a3b6d2e91",
  "read": false
}
  • Read state is a person's. An API key has none, so it gets read: false; a token or a session marks it read for its member.

Retrieve an attachment of a message

GET /inbox/conversations/{conversation_id}/messages/{message_id}/attachments/{attachment_id}

A file a customer's message carried, with a link to download it.

Path parameters

  • conversation_idstringRequired

    The conversation's ID.

  • message_idstringRequired

    The message's ID.

  • attachment_idstringRequired

    The attachment's ID, from the message's attachments.

Request

curl -X GET "https://api.rasket.com/inbox/conversations/0192f8e1-7a40-7c55-b1e3-0f0a3b6d2e91/messages/0192f8e1-7a52-7d10-8c44-91a0b2c3d4e5/attachments/5f2c9a1b-7e3d-4c8a-9b1f-2e6d0a4c8b73" \
  -H "Authorization: Bearer $RASKET_API_KEY" \
  -H "User-Agent: acme-billing/1.0"

Response 200

{
  "object": "inbox_attachment",
  "id": "5f2c9a1b-7e3d-4c8a-9b1f-2e6d0a4c8b73",
  "filename": "damage-report.pdf",
  "content_type": "application/pdf",
  "size": 20481,
  "download_url": "https://api.rasket.com/emails/receiving/0192f8e1-7a4f-7b20-a1c3-6d5e4f3a2b10/attachments/5f2c9a1b-7e3d-4c8a-9b1f-2e6d0a4c8b73/download?expires=1791105492&token=1f0c…",
  "expires_at": "2026-10-04T09:18:12.000Z"
}
  • download_url is valid for 15 minutes and takes no Authorization header. It is null for a part we recorded but did not keep.
  • An outbound message's files are on its sent email.