WhatsApp Inbox API

Версия 1 · чтение переписки и черновики ответов для CRM и других проектов

Как это работает. Проект читает переписку и кладёт черновик ответа — по-русски (переведём сами на язык собеседника, испанский — уругвайский) или уже готовый текст. Черновик появляется в интерфейсе WhatsApp Inbox в поле ответа нужной переписки с пометкой «Черновик из …». Человек проверяет, при необходимости правит и отправляет. Отправить сообщение напрямую через API нельзя — это сделано намеренно, чтобы клиенту ничего не ушло без проверки.

Доступ и ключ

Базовый адрес: https://wa-me.im/api/v1. Все запросы и ответы — JSON в UTF-8, время — ISO 8601 (UTC) и миллисекунды Unix.

Каждый запрос с заголовком:

Authorization: Bearer <ключ>

Ключи выпускает владелец пространства: ⚙ Настройки → Ключи API → Создать. Ключ показывается один раз — сохраните его в менеджере паролей и передавайте в проект через переменные окружения, не записывайте в код. Ключ видит только номера своего пространства; его название попадает в поле source черновика. Отозвать ключ можно там же. Лимит — 120 запросов в минуту на ключ.

Номера, чаты и аккаунты

Аккаунты

GET/accounts

curl -H "Authorization: Bearer $WA_API_KEY" https://wa-me.im/api/v1/accounts
{ "accounts": [
  { "account": "business", "title": "Business", "connected": true, "phone": "+59897323353", "name": "Fluenta" },
  { "account": "personal", "title": "Личный", "connected": true, "phone": "+59892804681", "name": null }
] }

Список чатов

GET/chats

ПараметрОписание
accountАккаунт (необязательно; без него — все)
qПоиск по имени или цифрам номера
limitСколько вернуть, по умолчанию 50, максимум 500. Сортировка — по последнему сообщению, новые сверху
curl -H "Authorization: Bearer $WA_API_KEY" "https://wa-me.im/api/v1/chats?account=business&q=belu"
{ "chats": [ {
  "account": "business", "chat": "5493513049992@s.whatsapp.net", "phone": "+5493513049992", "name": "Belu",
  "last_message_at": "2025-10-13T15:56:52.000Z", "last_message": "[голосовое сообщение]", "last_from_me": false,
  "messages": 10, "unread": 2, "pending_drafts": 0
} ] }

Сообщения переписки

GET/chats/{account}/{phone}/messages

ПараметрОписание
limitПо умолчанию 50, максимум 500
beforeТолько сообщения раньше этого момента (мс Unix) — листать историю назад
afterТолько новее этого момента (мс Unix) — забирать новые с прошлого запроса

Сообщения всегда идут от старых к новым. Без before/after — последние limit штук.

curl -H "Authorization: Bearer $WA_API_KEY" \
  "https://wa-me.im/api/v1/chats/business/5493513049992/messages?limit=20"
{ "account": "business", "chat": "5493513049992@s.whatsapp.net", "phone": "+5493513049992",
  "messages": [ {
    "id": "3AC8667914EFE184D44F", "direction": "in", "at": "2025-10-13T15:56:52.000Z", "ts": 1760371012000,
    "sender": { "phone": "+5493513049992", "name": "Belu" },
    "type": "voice", "text": "Buen día, feliz comienzo de semana…",
    "translation_ru": "Доброе утро, хорошего начала недели…",
    "media_url": "/api/v1/media/business/3AC8667914EFE184D44F", "status": null
  }, {
    "id": "3EB0…", "direction": "out", "at": "…", "ts": 1760372000000, "sender": null,
    "type": "text", "text": "¡Hola, Belu! Gracias por escribir.", "translation_ru": "Привет, Белу! Спасибо, что написала.",
    "media_url": null, "status": "read"
  } ] }
ПолеЗначение
directionin — от собеседника, out — наше
typetext, image, video, voice, document, sticker
textТекст или подпись к вложению; у голосовых — распознанная речь, если её уже распознали в интерфейсе
translation_ruВходящие: перевод на русский (null — ещё не переводили, "" — перевод не нужен). Наши: русский исходник ответа, если писали через перевод
statusТолько у наших: pending, sent ✓, delivered ✓✓, read (синие ✓✓), played (голосовое прослушано), error; null — неизвестно

Файл вложения

GET/media/{account}/{id}

Отдаёт сам файл (картинку, PDF, голосовое ogg) с правильным Content-Type. Адрес — из поля media_url. Старые файлы, которых уже нет на серверах WhatsApp, отвечают 404 media_unavailable.

Создать черновик ответа

POST/drafts

ПолеОписание
accountАккаунт, по умолчанию business
phone или chatНомер собеседника или идентификатор чата. Чат может быть новым — он появится в списке с пометкой «черновик»
ruТекст по-русски. Если text не передан, переведём на язык собеседника с учётом переписки (испанский — уругвайский, тон и обращение как в переписке)
textГотовый текст на языке собеседника — будет отправлен как есть. Можно передать вместе с ru, тогда перевода не будет
langЯзык перевода (es, en, pt…), по умолчанию — язык собеседника
translatefalse — не переводить ru сейчас (переведёт человек кнопкой в интерфейсе)
attachmentКартинка или файл: { "url": "https://…/invoice.pdf" } — скачаем сами (http/https, до 64 МБ, 30 с), или { "data": "<base64>", "name": "счёт.pdf", "mime": "application/pdf" }. name и mime необязательны — определим по ссылке и расширению. JPG/PNG/WebP уйдут фото, MP4/MOV — видео, остальное — документом; текст черновика станет подписью
noteПометка для человека, видна над полем ответа: «Счёт № 512», «ответ на запрос цены»
external_idВаш идентификатор (например, id задачи в CRM). Повторный запрос с тем же external_id, пока черновик не обработан, не создаёт дубль — вернётся существующий с "duplicate": true
sourceОткуда черновик, по умолчанию — имя ключа (crm)

Нужен хотя бы один из ru / text / attachment. Перевод занимает 1–3 секунды.

curl -X POST https://wa-me.im/api/v1/drafts \
  -H "Authorization: Bearer $WA_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "account": "business",
    "phone": "+54 9 351 304-9992",
    "ru": "Добрый день! Счёт на оплату отправили на почту. Если будут вопросы — пишите.",
    "note": "Счёт № 512",
    "external_id": "deal-512-invoice"
  }'
HTTP/1.1 201 Created
{ "draft": {
  "id": "drf_3f9c2a7b1e4d4c0a9b12", "account": "business", "chat": "5493513049992@s.whatsapp.net", "phone": "+5493513049992",
  "ru": "Добрый день! Счёт на оплату отправили на почту. Если будут вопросы — пишите.",
  "text": "¡Buen día! Te mandamos la factura por mail. Cualquier duda, escribinos.",
  "lang": "es", "source": "crm", "note": "Счёт № 512", "external_id": "deal-512-invoice",
  "status": "pending", "message_id": null,
  "created_at": "2026-10-24T13:30:00.000Z", "updated_at": "2026-10-24T13:30:00.000Z"
} }

С вложением:

curl -X POST https://wa-me.im/api/v1/drafts \
  -H "Authorization: Bearer $WA_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "phone": "+59899123456",
    "ru": "Отправляю счёт на оплату за ноябрь.",
    "attachment": { "url": "https://crm.example.com/files/invoice-512.pdf", "name": "Factura-512.pdf" },
    "external_id": "invoice-512"
  }'

В ответе у черновика появится "attachment": { "name", "mime", "size", "url": "/api/v1/drafts/drf_…/attachment" }. В интерфейсе вложение прикрепится к полю ответа вместе с текстом — человек увидит превью и отправит.

GET/drafts/{id}/attachment

Файл вложения черновика.

Список черновиков

GET/drafts

ПараметрОписание
account, phone / chatФильтр по аккаунту и собеседнику
statuspending — ждёт человека, sent — отправлен (в message_id — id сообщения), discarded — отклонён
limitПо умолчанию 100, максимум 500; новые сверху
curl -H "Authorization: Bearer $WA_API_KEY" "https://wa-me.im/api/v1/drafts?status=sent&limit=20"

Черновик по id

GET/drafts/{id}

Текущее состояние — удобно проверять, отправил ли человек ответ. После отправки status = "sent", а text остаётся в том виде, в каком его предложили (человек мог поправить — фактический текст ищите по message_id в сообщениях).

DELETE/drafts/{id}

Отозвать черновик, пока он не отправлен (status → "discarded"). Для отправленного — 409 draft_not_pending.

Ошибки

{ "error": { "code": "account_not_found", "message": "Нет аккаунта «biz». Список: GET /api/v1/accounts" } }
HTTPcodeКогда
400bad_requestНет номера, нет текста, номер не похож на номер
401unauthorizedНет ключа или ключ неверный
404account_not_found, draft_not_found, media_unavailable, not_foundНет такого аккаунта, черновика, файла или метода
402quota_exceededИсчерпан месячный лимит перевода бесплатного тарифа (черновик с ru без text)
429rate_limitedБольше 120 запросов в минуту
409draft_not_pendingЧерновик уже отправлен или отклонён
413attachment_too_largeВложение больше 64 МБ
422attachment_fetch_failedНе удалось скачать вложение по ссылке (ошибка сети, таймаут, не 2xx)
500internalНапример, недоступен сервис перевода — повторите позже или передайте готовый text

Пример интеграции (Node.js)

const WA = 'https://wa-me.im/api/v1'
const headers = { Authorization: `Bearer ${process.env.WA_API_KEY}`, 'Content-Type': 'application/json' }

// 1. Последние сообщения клиента — показать в карточке сделки
const { messages } = await fetch(`${WA}/chats/business/5493513049992/messages?limit=30`, { headers }).then(r => r.json())

// 2. Черновик ответа по-русски — менеджер проверит и отправит в WhatsApp Inbox
const { draft } = await fetch(`${WA}/drafts`, {
  method: 'POST', headers,
  body: JSON.stringify({ phone: '+5493513049992', ru: 'Здравствуйте! Договор готов, отправить на почту?', external_id: 'deal-77' }),
}).then(r => r.json())

// 3. Позже — узнать, ушёл ли ответ
const state = await fetch(`${WA}/drafts/${draft.id}`, { headers }).then(r => r.json())
console.log(state.draft.status) // pending | sent | discarded

Журналы

Каждый запрос к API пишется в data/events.log: ключ, метод, путь, код ответа и время (тела запросов и ключи — нет). Ошибки со стеком — в data/errors.log. Если интеграция получает 5xx — смотрите там по времени запроса.