Channelsadvanced

Send an outbound message via the API

Create a conversation programmatically with POST /v1/conversations/outbound. Pass an externalReference for idempotent retries, a contact, a subject, and optionally the channel, tags, and custom fields.

May 11, 20268 min read

Send an outbound message via the API

You’ll use this when you have a touchpoint outside Atender — a custom in-app chat, a marketplace inbox, a legacy tool — and you want the resulting conversation to land in Atender’s inbox.

Before you start

  • A tenant API key with the conversations:write scope. Generate one in Settings → API Keys if you don’t have one yet.
  • Decide on an externalReference scheme for your conversations. This is a string you supply that uniquely identifies the conversation in your system — it makes retries safe.

Request

POST https://YOUR-ATENDER-HOST/v1/conversations/outbound

Headers:

Authorization: Bearer sa_live_xxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

Body:

{
  "externalReference": "your-system-123",
  "contact": {
    "email": "customer@example.com",
    "name": "Optional Name",
    "phone": "+15551234567"
  },
  "subject": "Order #4521 — refund request",
  "channel": "email",
  "outboundContext": {
    "originalMessage": "The customer's original message body",
    "sentAt": "2026-05-11T09:00:00Z",
    "metadata": { "source": "shopify" }
  },
  "tags": ["refund", "vip"],
  "customFields": { "order_id": "4521" }
}

Required fields

  • externalReference — string (max 255) — Unique per tenant. Reusing the same reference returns 409 — useful for safely retrying network failures.
  • contact.email — string — Valid email. Atender uses this to match (or create) a contact.
  • subject — string — Conversation subject.

Optional fields

  • contact.name — string — Contact’s full name. If omitted, the email’s local part is used.
  • contact.phone — string — Contact’s phone number.
  • channel — enum — One of email (default), messenger, sms, phone, voice, whatsapp, webchat, amazon. Tag the conversation with the channel it really came from in your system.
  • outboundContext.originalMessage — string — The first message body as plain text.
  • outboundContext.originalHtml — string — The first message body as HTML, if you have it.
  • outboundContext.sentAt — string — ISO timestamp of when the message was originally sent.
  • outboundContext.metadata — object — Free-form metadata for your own use.
  • tags — string[] — Tag slugs to attach to the conversation. Slugs that don’t exist will be ignored.
  • customFields — object — Custom-field values keyed by field slug.

Response

On success, you get a 201 Created with the conversation:

{
  "id": "...",
  "externalReference": "your-system-123",
  "status": "active",
  ...
}

Verify it worked

  • Open the inbox in Atender. The new conversation appears in Active, assigned to the team that owns the channel (or the default team if no routing rules match).
  • Reply to the conversation in Atender. If you’ve also subscribed to webhook events, your server will receive a message.sent event with the reply payload — that’s how you ship the agent’s reply back to wherever the customer is.

Errors to handle

  • 400 — Validation error — Check required fields. The response body has errors[] pointing to the offending fields.
  • 401 — Bad or missing API key — Re-check the Authorization header.
  • 403 — Wrong scope — Your API key needs conversations:write.
  • 409externalReference already used — A conversation already exists for that reference. Use a different reference, or fetch the existing conversation by reference.
  • 5xx — Server error — Retry with exponential backoff. Because you supplied an externalReference, a retry that succeeds after a 5xx will not create a duplicate.

Patterns

  • Always supply an externalReference. It is what makes retries safe. If your network blip causes you to receive a 5xx but the conversation was actually created, your retry will get a 409 and you can move on.
  • Use the channel field honestly. If the conversation came from Instagram, set channel: "messenger". The channel badge in the inbox is set from this field, and downstream filters and analytics depend on it.
  • Store the returned id alongside your externalReference so you can correlate later. You’ll need it to fetch the conversation, push replies, or correlate webhook events.

Limits

  • The externalReference must be unique per tenant. Conflicts return 409.
  • Validation enforces a max length of 255 on externalReference and a valid email on contact.email.

See also

Tags

How To

See Atender in action

Book a personalized demo and see how AI-powered customer service with expert humans can transform your support operation.