Skip to main content
AlonChat

Chat API

Integrate AlonChat conversations into your applications via the REST API

Chat API#

Send messages and receive AI responses programmatically through the AlonChat Chat API.


Overview#

The Chat API lets you:

  • Send a customer message to your AI agent
  • Receive a complete reply or a streaming response
  • Continue multi-turn conversations with a conversation ID
  • Track credits used for each request

API, MCP, and CLI access are available on every paid plan. Active trials may access gated features during the trial, subject to trial limits.

The same endpoint is documented on your agent's Deploy → API page.


Quick Start#

1. Get Your API Key#

  1. Go to Project Settings → API Keys and create a key (optionally restrict it to one agent).
  2. Open your agent's Deploy → API page for the endpoint and Agent ID.
  3. Send the key as a Bearer token from your server only.

Keys look like sk-… and are shown once at creation.

2. Make Your First Request#

bash
curl -X POST https://alonchat.com/api/v1/chat/{agentId} \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: first-message-001" \
  -d '{
    "message": "Hello, what are your business hours?"
  }'

3. Handle the Response#

json
{
  "response": "We're open Monday–Saturday, 9AM to 6PM. Closed on Sundays and holidays!",
  "conversation_id": "550e8400-e29b-41d4-a716-446655440000",
  "credits_used": 5,
  "credits_remaining": 995
}

Save conversation_id and send it on later requests to keep the same thread.


Authentication#

Code
Authorization: Bearer YOUR_API_KEY

API keys are managed in Project Settings → API Keys. You can optionally restrict a key to one agent. See the Authentication guide.

Security: Use API keys only on your server. Never put them in frontend code, mobile apps, or public repositories.


Endpoint#

POST /api/v1/chat/{agentId}

Request Body#

FieldTypeRequiredDescription
messagestringYesUser message (1–10,000 characters). Still required when you send a Workflow interaction.
conversation_iduuidNoContinue an existing conversation. Omit to start a new one.
streambooleanNoSet true for Server-Sent Events (SSE). Default false.
idempotency_keystringYes1–255 characters. Required for a billable turn. Can also be sent as the Idempotency-Key or X-Idempotency-Key header.
interactionobjectNoA workflow_button selection: type, runId, nodeId, and payload from the previous presentation. It does not start an arbitrary Workflow.

Example (non-streaming)#

javascript
const response = await fetch(`https://alonchat.com/api/v1/chat/${agentId}`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    message: 'What products do you offer?',
    conversation_id: '550e8400-e29b-41d4-a716-446655440000',
    idempotency_key: crypto.randomUUID(),
  }),
})

const data = await response.json()
console.log(data.response)
console.log(data.conversation_id)
console.log(data.credits_used)

Success Response#

FieldTypeDescription
responsestringAgent reply text. Empty when the customer message was accepted while AI replies are paused.
conversation_iduuidConversation to continue on the next turn
credits_usednumberCredits consumed by this request
credits_remainingnumberCredits left after this request. Returned on chat even when the key cannot read billing.
presentationobjectPresent only when this turn has Workflow messages, buttons, or media to render. Version is 1.
customer_messageobjectPresent when the message was stored while AI replies are paused. ai_reply is paused.

The TypeScript SDK maps conversation_id, credits_used, credits_remaining, and customer_message to camelCase. presentation keeps the same name.

presentation can include ordered messages, buttons, image URLs, and media URLs. Render only the fields that are actually present. API chat does not reproduce a custom widget: forms use a conversational fallback, and asynchronous follow-ups are not part of this response. Test interactive widget layout in the embedded web widget, not with this endpoint alone.

To continue a Workflow button, send a new idempotency key and an interaction copied from that presentation. A selection that is no longer current returns 409 WORKFLOW_INTERACTION_STALE. Sending an interaction while AI replies are paused returns 409 AI_REPLY_PAUSED.

An identical completed request is replayed with 200 and X-AlonChat-Idempotent-Replay: true. That replay does not run the turn again. Diagnostic fields such as model and timing can also appear; do not depend on them.


Streaming Responses#

Set "stream": true to receive Server-Sent Events. Data lines contain JSON after data: . Network chunks can split a line, so buffer incomplete lines before parsing. The SDK also provides streamMessage(...) for this.

javascript
const response = await fetch(`https://alonchat.com/api/v1/chat/${agentId}`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    message: 'Tell me about your services',
    stream: true,
    idempotency_key: crypto.randomUUID(),
  }),
})

if (!response.ok || !response.body) {
  throw new Error(`Chat request failed: ${response.status}`)
}

const reader = response.body.getReader()
const decoder = new TextDecoder()
let buffer = ''

while (true) {
  const { done, value } = await reader.read()
  if (done) break

  buffer += decoder.decode(value, { stream: true })
  const lines = buffer.split('\n')
  buffer = lines.pop() ?? ''

  for (const line of lines) {
    if (!line.startsWith('data: ')) continue
    const event = JSON.parse(line.slice(6))

    if (event.type === 'token') {
      process.stdout.write(event.token)
    } else if (event.type === 'done') {
      console.log('\nConversation:', event.conversation_id)
      console.log('Credits used:', event.credits_used)
    } else if (event.type === 'error') {
      console.error(event.error)
    }
  }
}
TypeMeaning
tokenPartial reply text in token
action_startA tool started. Includes actionName.
action_completeA tool finished. Includes actionName and success.
gate_triggeredA safety or policy gate changed the turn. Includes decision and reason.
doneStream finished. Includes the same final fields as a non-streaming reply.
errorRequest failed mid-stream. The message is in error.

Handle any other type safely. A replayed stream sends one done event for the original reply.


Rate Limits#

The Chat API is rate-limited to 60 requests per minute per API key.

Responses include rate-limit headers so you can track usage. When you exceed the limit, the API returns 429 with retry_after_seconds (and related limit fields). Back off before retrying.


Error Handling#

StatusMeaning
200Success, including an idempotent replay of the same completed turn
400Invalid body, or IDEMPOTENCY_KEY_REQUIRED
401Invalid or missing API key
402Insufficient credits (INSUFFICIENT_CREDITS), with credits_required and credits_remaining when known
403The key lacks chat, is outside its agent scope, or the plan does not allow this agent
404Agent not found
409In-flight duplicate, idempotency conflict, uncertain earlier turn, paused AI interaction, or stale Workflow
429Rate limited
500Server error
503Service temporarily unavailable

Chat errors are a flat JSON object, not the operation receipt used by other project operations. For example:

json
{
  "error": "Rate limit exceeded. Please slow down.",
  "retry_after_seconds": 30,
  "limit": 60,
  "remaining": 0
}

A 409 body includes a stable code:

CodeMeaning
REQUEST_IN_PROGRESSThis key is still processing. Wait and send the same request again.
IDEMPOTENCY_CONFLICTThis key was already used for a different message.
OUTCOME_UNCERTAINThe earlier turn must be reconciled before another attempt. Do not mint a new key.
AI_REPLY_PAUSEDA Workflow interaction was sent while AI replies are paused.
WORKFLOW_INTERACTION_STALERead the latest turn and select a current button.

Best Practices#

  1. Store conversation_id so multi-turn chats keep context.
  2. Send a new idempotency_key for every new message, and reuse it only for that same request.
  3. Render presentation only when it is present, and test custom widgets in the web widget.
  4. Use streaming when you want progressive UI updates.
  5. Keep keys server-side and rotate them if they leak.
  6. Watch credits via credits_used / credits_remaining and your Usage page.