Bots API

Use Sendeasy's AI from your own application — an assistant inside your product, a routine in your backend, a screen that summarizes documents — without going through WhatsApp.

The bot carries the instructions: you create and edit it in the panel, and pass its botId here. Changing how the AI behaves means editing the bot, not changing your code.

Prerequisites

  1. Project API Token — in Integrations → WABAAPI Tokens section, where you create a named token and can revoke it. It is the same token used by the WABA API and the Email API: one per project, not one per product.
  2. A bot created in the panel, with its instructions and knowledge sources — see /en/bot. Keep the botId.
  3. Bot credits available in the project plan.

Use GET /api/v1/ai/health to check the integration without spending credits.

Authentication

Required header:

Authorization: Bearer <api_token>

The token identifies the project, and it is what authorizes the botId: a bot from another project is rejected, even if you know its id.

Endpoints

MethodEndpointPurposeCredit
POST/api/v1/ai/completionGenerate text with the bot's prompt1 per generation
POST/api/v1/ai/extractExtract content from a PDF1 per file
POST/api/v1/ai/searchSearch the bot's knowledge basefree
GET/api/v1/ai/healthDiagnostics: is the integration up?free

Limit: 60 requests per minute per API Token (429 ERR_PUBLIC_AI_RATE_LIMIT). Counting is per token, not per IP — several servers sharing one token share the quota, and the same server with different tokens gets separate quotas.

Text generation

POST /api/v1/ai/completion

Payload

FieldTypeRequiredNotes
promptstringYesthe request itself, up to 120,000 characters
botIdstringOne of the twouses that bot's instructions and knowledge
instructionsstringOne of the twostandalone system prompt, up to 60,000 characters
responseFormatstringNotext (default) or json
timeoutMsnumberNobetween 1,000 and 90,000; service default if omitted

Pass botId or instructions. With neither, the route answers 400 instead of spending a credit to return out-of-context text.

Example

curl --location 'https://backend.sendeasy.app/api/v1/ai/completion' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --data '{
    "botId": "your-bot-id",
    "prompt": "Summarize the return policy in two paragraphs."
  }'

Success response:

{
  "success": true,
  "result": "The return policy allows returns within 30 days..."
}

With "responseFormat": "json", the answer comes parsed in dados instead of result — useful when the prompt asks for a structure and you would rather not parse text:

{
  "success": true,
  "dados": { "prazo_dias": 30, "exige_nota": true }
}

PDF extraction

POST /api/v1/ai/extract

multipart/form-data upload with the file in the file field. PDF only, up to 25 MB.

FieldTypeRequiredNotes
filefileYesthe PDF, application/pdf
modestringNotext (default) returns the text in result; other modes return the payload in dados
curl --location 'https://backend.sendeasy.app/api/v1/ai/extract' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --form 'file=@"/path/contract.pdf"' \
  --form 'mode="text"'
{
  "success": true,
  "result": "SERVICE AGREEMENT..."
}

Reading falls back to OCR for scanned PDFs, so large files take a while. If the AI cannot recognize the content, the answer is 502 with the reason — resending the same file will not help.

POST /api/v1/ai/search

Retrieves excerpts from the bot's sources without generating text. Use it to ground an answer of your own, or to show the user where the information came from.

FieldTypeRequiredNotes
botIdstringYeswhich bot to search
querystringYeswhat to look for, up to 2,000 characters
topKnumberNohow many excerpts to return, from 1 to 8
filtersobjectNonarrows the search to certain documents (see below)

filters takes two fields, both lists of file-name patterns (% matches any stretch):

FieldEffect
incluirArquivossearches only the matching documents; omitted, it scans the whole base
excluirArquivosdrops matching documents, even if they were included
{
  "botId": "your-bot-id",
  "query": "warranty period",
  "filters": {
    "incluirArquivos": ["manual-%", "returns-policy.pdf"],
    "excluirArquivos": ["draft-%"]
  }
}

Useful when the base is large and you already know where the answer lives: without a filter, one long document can take up the result slots and drown out what matters.

curl --location 'https://backend.sendeasy.app/api/v1/ai/search' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --data '{
    "botId": "your-bot-id",
    "query": "warranty period",
    "topK": 3
  }'
{
  "success": true,
  "trechos": [
    {
      "texto": "The legal warranty is 90 days for durable goods...",
      "procedencia": "customer-manual.pdf",
      "score": 0.82
    }
  ]
}

No credit is charged: this is content retrieval, not generation. If the search fails, the answer carries trechos: [] instead of an error — without context your answer loses grounding, it does not cease to exist.

Integration diagnostics

GET /api/v1/ai/health

Free, and it never calls the model. It answers the two questions behind almost every integration failure: is the AI service up, and is there still balance?

curl --location 'https://backend.sendeasy.app/api/v1/ai/health' \
  --header 'Authorization: Bearer YOUR_API_TOKEN'
{
  "success": true,
  "companyId": 42,
  "botrag": { "ok": true, "latenciaMs": 210 },
  "creditos": { "disponivel": 4820, "mes": "9/2026" },
  "checkedAt": "2026-09-01T12:30:00.000Z"
}
  • botrag.ok: false — the AI service is unavailable; a detalhe field carries the cause. Nothing to do on your side other than retry later.
  • creditos.disponivel: 0 — the project ran out of credits and the generation routes will answer 402. Renew the plan or wait for next month's allowance.

Which bots a token can reach

botId is resolved inside your API Token's project. A token from one project cannot use another project's bot, even knowing its id: the route answers 403 without generating anything or touching your balance. A bot that doesn't exist answers 404.

This applies to completion and search — the two routes that resolve a bot. extract doesn't use botId.

Credits and refunds

  • Every generation (completion, extract) deducts 1 bot credit from the project.
  • With no credits, the route answers 402 ERR_NO_BOT_CREDITS before any charge.
  • If generation fails after the charge, the credit is refunded automatically and the route answers 502.
  • search and health cost nothing.

Error codes

HTTPerrorWhen it happens
400validation messageinvalid payload, missing prompt, neither botId nor instructions, file that is not a PDF
400INVALID_JSONbody is not valid JSON
400FILE_TOO_LARGEPDF above 25 MB
401ERR_API_TOKEN_NOT_PROVIDED / ERR_API_TOKEN_INVALID_FORMAT / ERR_API_TOKEN_INVALID / ERR_API_TOKEN_AUTHENTICATION_FAILEDmissing or malformed header, invalid or revoked token
402ERR_NO_BOT_CREDITSproject has no bot credits (nothing was charged)
403authorization messagebotId of a bot that does not belong to the token's project
404bot messagebotId does not exist
413PAYLOAD_TOO_LARGEJSON body above 10 MB
429ERR_PUBLIC_AI_RATE_LIMITmore than 60 requests per minute
502plain-text messagegeneration failed (credit refunded); when the AI knows why, the reason comes in the message
504GATEWAY_TIMEOUTgeneration exceeded the time limit

Bots API × bot on WhatsApp

The same bot, two paths — what changes is who drives the conversation:

Bots API (/api/v1/ai/*)Bot in support
Who callsyour applicationthe ticket, when it enters the queue
Conversationeach call stands aloneSendeasy keeps the history in the ticket
Typical useassistant and automations in your productsupport on WhatsApp

Essa informação foi útil?