aethexDocs

API Reference

Text conversations

The customer side of your numbers: every thread on a number that receives texts, human handoff, and campaigns. A thread appears the first time somebody texts you, so there is nothing to create. Replies leave from the number the customer wrote to, never from another of yours.

Base URL
https://api.aethexai.com/api/v1
Endpoints
15
Scopes
sms_inbox:readsms_inbox:writesms_campaigns:readsms_campaigns:write
GET/sms-inbox/summary

Whether the inbox needs opening at all.

Inbox summary

Unread messages, how many threads carry them, and how many customers are waiting on a person. Counted across every number you own.

GET/sms-inbox/threads

Your customers, most recent first.

List threads

One thread per customer per number. Filter by number, by status, or by mode. 'mode=human' is the queue somebody has to answer.

Path & Query

6
  • phone_number_iduuidoptional

    Only threads or campaigns on this number of yours.

  • customerstringoptional

    Only threads with this customer, in E.164 with the leading plus. Spaces and punctuation are ignored. A national spelling, a missing plus or a blank value returns 422 rather than an empty list. More than one thread can come back — one per number of yours the customer has exchanged messages on — most recent first.

  • statusstringoptional

    open, closed or opted_out.

  • modestringoptional

    agent or human. 'human' is the queue somebody has to answer.

  • offsetintegeroptional

    How many rows to skip. Defaults to 0.

  • limitintegeroptional

    How many rows to return. Defaults to 50, up to 200.

GET/sms-inbox/threads/:thread_id

A customer's state on one of your numbers.

Read one thread

Status, mode, unread count, and when they last wrote. The message bodies are on the timeline endpoint below.

Errors

1
404Not found

No thread with that id on your account.

Check the id, or list the threads to find it.

GET/sms-inbox/threads/:thread_id/messages

Everything said, newest first.

Thread timeline

Every turn this customer has exchanged on this number, across all their conversations. The agent starts a fresh one after a long gap, and the timeline spans the gap. 'author' is 'agent', 'system', or the operator who wrote it. 'delivery_status' reads 'failed' when the carrier refused a reply. A message and the reply written with it share one 'created_at'; when timestamps tie, the list order is authoritative, so the reply comes first.

Path & Query

2
  • offsetintegeroptional

    How many rows to skip. Defaults to 0.

  • limitintegeroptional

    How many rows to return. Defaults to 50, up to 200.

POST/sms-inbox/threads/:thread_id/read

Clear its unread count.

Mark a thread read

Sets the unread count to zero and stamps when it was read. Does not change who is answering.

POST/sms-inbox/threads/:thread_id/mode

Switch between the agent and a person.

Hand a thread over, or back

While a thread reads 'human' the agent stops replying, and the customer's messages are still stored and counted. Set it back to 'agent' when you are done. A customer asking for a person throws this switch themselves.

Request body

3
  • modestringrequired

    'agent' or 'human'.

  • reasonstringoptional

    Why it was handed over. Shown in the thread.

  • assigned_tostringoptional

    Who owns it now. Free text: an email, a name.

Errors

1
422Invalid request

'mode' was neither 'agent' nor 'human'.

Send one of the two.

PATCH/sms-inbox/threads/:thread_id

Bookkeeping, not routing.

Close or assign a thread

Closing is bookkeeping: the customer reopens the thread by writing again. 'opted_out' is not settable here. It is the customer's decision, recorded when they text STOP, and lifted only when they text START.

Request body

2
  • statusstringoptional

    'open' or 'closed'.

  • assigned_tostringoptional

    Who owns the thread. Send null to unassign.

Errors

1
409Conflict

This customer has opted out, so the thread cannot be reopened from here.

Nothing to do. The thread reopens when they text START.

POST/sms-inbox/threads/:thread_id/messages

Send one message yourself, from the number they wrote to.

Reply as a person

Accepted for delivery and written into the thread with your name on it. Does not switch the thread to human mode: say one thing and leave the agent running, or take the thread over first with the mode endpoint. recorded: false means the carrier took the message and the customer has it, but the entry could not be written to the thread; message_id and conversation_id are then absent. It is never a reason to send again.

Request body

2
  • bodystringrequired

    The text to send, as written. Up to 1600 characters.

  • authorstringoptional

    Who is replying. Shown in the timeline; defaults to 'operator'.

Errors

2
409Conflict

This customer has opted out of your messages on every one of your numbers.

Nothing can be sent until they text START. Reach them another way.

422Invalid request

'body' was blank.

Send some text.

POST/sms-campaigns

One message to a list, paced, nothing sent yet.

Create a campaign

Created as a draft, or as 'scheduled' when you pass 'scheduled_at'. Nothing leaves until it is started or its time comes. Everything refusable is refused here rather than one recipient at a time: a value missing from a row, a message too long once filled, a number that cannot send. Recipients who have opted out are marked 'skipped' before it starts, and re-checked before every send.

Request body

8
  • phone_number_iduuidrequired

    The number it leaves from. It must receive texts (sms_inbound), so a recipient's STOP reaches somebody.

  • namestringrequired

    What you will recognise it by.

  • bodystringrequired

    The message, with {lowercase_name} holes filled per recipient. Up to 480 characters once filled.

  • recipientsarrayrequired

    Up to 50,000 rows of {to, values}. 'to' is E.164 with the plus; spaces and dashes are tolerated. A repeated number is kept once.

  • rate_per_minuteintegeroptional

    Messages a minute, 1 to 600. Defaults to 60.

  • scheduled_atstringoptional

    When to start. Leave unset to create a draft and start it by hand.

  • acknowledge_no_repliesbooleanoptional

    Run it even though this number does not receive texts. A recipient replying STOP would reach nobody, and on markets where the carrier does not filter STOP for you, their request reaches no one at all. The choice is recorded on the campaign.

  • webhook_urlstringoptional

    HTTPS URL that receives a signed sms.campaign.paused if the worker stops this campaign on its own: the number gone inactive, the carrier refusing the sending account, five identical refusals in a row, the account out of credit. A pause you ask for is not reported. Needs your account webhook secret. Leave unset and nobody is told.

Errors

3
409Conflict

The number does not receive text messages.

Turn on sms_inbound for it, or send acknowledge_no_replies=true.

409Conflict

The carrier says this number cannot carry text messages at all, or it sits on a shared account.

Use an SMS-capable number on your own carrier account. acknowledge_no_replies does not lift this.

422Invalid request

A row has no value for one of the message's holes, is not E.164, or renders over the length limit.

The error names the row. Fix it and resend the list.

GET/sms-campaigns

What has run and what is running.

List campaigns

Newest first, with the counters: sent, failed, and skipped. 'skipped' is somebody deliberately not written to, almost always an opt-out.

Path & Query

4
  • phone_number_iduuidoptional

    Only threads or campaigns on this number of yours.

  • statusstringoptional

    draft, scheduled, running, paused, completed, cancelled or failed.

  • offsetintegeroptional

    How many rows to skip. Defaults to 0.

  • limitintegeroptional

    How many rows to return. Defaults to 50, up to 200.

GET/sms-campaigns/:campaign_id

Its state and its counters.

Read one campaign

'replies_acknowledged_at' is set when the campaign was allowed to leave from a number that does not take replies, and names when that was decided.

Errors

1
404Not found

No campaign with that id on your account.

Check the id.

GET/sms-campaigns/:campaign_id/recipients

Who was reached, who was not, and why.

Campaign recipients

The list a campaign is judged on. 'pending' has not been attempted, 'sending' is in flight, 'sent' left for the carrier, 'failed' carries the carrier's verdict, and 'skipped' was deliberately not written to.

Path & Query

3
  • statusstringoptional

    pending, sending, sent, failed or skipped.

  • offsetintegeroptional

    How many rows to skip. Defaults to 0.

  • limitintegeroptional

    How many rows to return. Defaults to 50, up to 200.

POST/sms-campaigns/:campaign_id/start

Begin sending, within the minute.

Start a campaign

Clears any scheduled time, because asking to start is asking to stop waiting. A worker picks it up on the next sweep. Pause and cancel take effect at the next message, not the next batch.

Errors

1
409Conflict

The campaign is completed, cancelled or failed.

Create a new campaign. A finished one cannot be restarted.

POST/sms-campaigns/:campaign_id/pause

Stop after the message in flight.

Pause a campaign

Takes effect at the next message. Start it again whenever you like; the recipients already sent are not sent again.

Errors

1
409Conflict

The campaign is not running or scheduled.

Nothing to pause.

POST/sms-campaigns/:campaign_id/cancel

Stop for good.

Cancel a campaign

What was already sent stays sent. Nothing else goes out, and the campaign cannot be started again.

Errors

1
409Conflict

The campaign is already completed, cancelled or failed.

Nothing to cancel.