Call your chatbots from your own software over HTTP. Issue keys, ask questions, keep multi-turn conversations, and revoke access at any time. Pro plan only.
If you lose a key, revoke it and create another. Revoking takes effect immediately.
Send the key as a Bearer token on every request:
Authorization: Bearer aimy_sk_your_key_here
POST https://aimy.com.my/chat/api/v1/chat
curl -X POST https://aimy.com.my/chat/api/v1/chat \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "What is the refund policy?",
"chatbot_id": 170
}'
Request fields:
message — required. Up to 8000 characters.chatbot_id — required unless the key is pinned to a chatbot. Get the ids from GET /api/v1/chatbots.conversation_id — optional. Omit it to start a new conversation; the response returns one. Pass the same value again to continue that conversation.A successful response:
{
"success": true,
"answer": "Refunds are available within 30 days ...",
"conversation_id": "8f2c1a7b9d0e4f6a1b2c3d4e",
"chatbot": { "id": 170, "name": "Support Bot" },
"citations": [ { "name": "policy.pdf", "page": 4, "snippet": "..." } ],
"sources": [ { "document": "policy.pdf", "page": 4, "preview": "...", "score": 0.81 } ]
}
citations and sources follow the Sources switch on the chatbot's row in the Chatbots page. With it off, both arrays come back empty — the fields are always present, so your code never has to check whether the key exists.Pass the conversation_id you got back on the first call, and the chatbot remembers what was said:
// First call - no conversation_id
{"message": "Do you ship to Sabah?"}
-> {"answer": "Yes ...", "conversation_id": "8f2c1a7b9d0e4f6a1b2c3d4e"}
// Follow-up - same conversation_id
{"message": "How long does it take?",
"conversation_id": "8f2c1a7b9d0e4f6a1b2c3d4e"}
You may also supply your own id (1–64 characters, letters, digits, _ or -) — your own ticket or session number, for instance. Conversations appear in History labelled with the key's name.
GET https://aimy.com.my/chat/api/v1/chatbots
curl https://aimy.com.my/chat/api/v1/chatbots \
-H "Authorization: Bearer YOUR_KEY"
{
"success": true,
"pinned": false,
"chatbots": [
{ "id": 170, "name": "Support Bot", "active": true, "documents": 12 }
]
}
pinned: true means the key is locked to the one chatbot listed, and you can omit chatbot_id when asking questions.
Every failure has the same shape. Branch on code — the message is for humans and may be reworded.
{
"success": false,
"error": { "code": "rate_limited", "message": "Too many requests..." }
}
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | Missing or malformed field |
| 401 | unauthorized | Key missing, invalid, or revoked |
| 402 | quota_exceeded | Your account is out of tokens, or has no active plan |
| 403 | forbidden_plan | The API isn't included in your plan |
| 403 | chatbot_not_allowed | This key is pinned to a different chatbot |
| 404 | chatbot_not_found | No such chatbot in your company |
| 409 | chatbot_inactive | The chatbot is switched off |
| 429 | rate_limited | Too many requests — see Retry-After |
| 503 | busy | Under load; retry shortly |
Each key has its own limit, set when you create it (60 requests per minute by default, adjustable up to 6000). Every response carries:
X-RateLimit-Limit — the key's limitX-RateLimit-Remaining — how many are left in the current minuteA 429 also carries Retry-After in seconds. Rate limits are separate from your plan's token quota — you can be inside your rate limit and still hit quota_exceeded.
The Developer page shows each key's last-used time and its call count over the last 30 days. Answers count toward your plan's token usage exactly like any other channel, and every conversation is saved to History.