Programadores
Documentação da API
Uma API REST autenticada por token para mensagens, modelos, contactos, campanhas, fluxos e o estado de entrega e o custo de cada mensagem. Crie uma chave de API em Ferramentas de programador na sua conta e autentique todas as chamadas com Authorization: Bearer <token>.
Há exemplos completos em PHP, Node.js, Python, Java e Ruby na documentação dentro da aplicação depois de criar uma conta.
Referência legível por máquinas: OpenAPI 3.1 (JSON) · Coleção Postman
Antes de começar
Autenticação
Todos os pedidos levam uma chave de API no cabeçalho Authorization como token Bearer. As chaves são criadas em Ferramentas de programador > Chaves de API e mostradas uma única vez.
Uma chave tem âmbitos: read (todos os GET), send (os endpoints de envio, as campanhas e o início de fluxos) e manage (criar, alterar e eliminar contactos, grupos, respostas automáticas, webhooks e modelos, mais as ações da caixa de entrada). Uma chave sem o âmbito recebe 403 com a indicação do âmbito em falta.
Uma chave pode expirar: uma chave expirada recebe 401 com "This API key has expired". Um token em falta ou desconhecido também é 401.
Uma chave sandbox valida todos os pedidos, regista a mensagem com o estado "sandbox" e não envia nada para o WhatsApp - desenvolva contra a API real sem uma linha de WhatsApp nem custos.
Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>
Limite de pedidos
60 pedidos por minuto por chave de API; os pedidos sem chave são contados por endereço IP.
Todas as respostas levam X-RateLimit-Limit e X-RateLimit-Remaining. Acima do limite, a resposta é 429 com statusCode 429, uma message e um cabeçalho Retry-After em segundos.
GET /api/usage indica o limite em rate_limit.per_minute. /api e /api/v2 partilham um único contador por chave.
HTTP/1.1 429 Too Many Requests
Retry-After: 42
{"statusCode": 429, "message": "Too many requests. Try again in 42 seconds."}
Idempotência
Envie um cabeçalho Idempotency-Key (1 a 128 caracteres, único por operação) nos endpoints POST que criam algo: os envios, as campanhas, os contactos, os grupos e as respostas automáticas.
A mesma chave com o mesmo pedido dentro de 24 horas devolve a resposta guardada com o cabeçalho Idempotent-Replayed: true, e nada volta a ser executado. Um cliente que repete o pedido depois de um timeout deixa de enviar duas vezes.
A mesma chave com um pedido diferente é 422; a mesma chave enquanto o primeiro pedido ainda está a correr é 409. Só as respostas 2xx e 4xx são guardadas, por isso um 5xx pode ser repetido com a mesma chave.
Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7
Datas e fusos horários
Todas as datas que a API devolve estão em UTC, em ISO-8601 com o respetivo desvio, seja qual for o fuso horário que a organização usa no painel.
As datas que envia (scheduled_at, since) são lidas como UTC, salvo se incluírem um desvio.
"created_at": "2026-10-05T09:30:00+00:00"
Erros
Todas as respostas são JSON com statusCode e message; um payload recusado acrescenta errors, um mapa de nome de campo para a lista de problemas.
400 entrada inválida; 401 chave em falta, inválida ou expirada; 403 âmbito, subscrição, limite do plano ou conta em análise; 404 uuid desconhecido, ou que pertence a outro espaço de trabalho; 409 conflito (uma transição de campanha impossível, uma Idempotency-Key ainda em curso); 422 recusado por uma regra (a janela de 24 horas, STOP, variáveis do modelo); 429 limite de pedidos; 500 culpa nossa.
As ações da caixa de entrada (assign, close e reopen em /api/conversations/{contact_uuid}) respondem 409 enquanto o ticketing está desligado em Definições > Tickets; ler a conversa e adicionar uma nota funcionam em qualquer caso.
Em /api (v1), uma recusa do próprio WhatsApp é um 200 com data.success false e o motivo em data.data.error (code, message, type). Em /api/v2 a mesma recusa é um HTTP 422 - consulte Versões.
{"statusCode": 400, "message": "The given data was invalid.", "errors": {"phone": ["The phone number is not valid."]}}
Paginação
Os endpoints de listagem aceitam page (a partir de 1) e per_page (predefinição 10, máx. 100; /api/messages usa 25 por predefinição) e estão ordenados do mais recente para o mais antigo.
Contactos, grupos, respostas automáticas, modelos, campanhas e registos de campanha respondem com data, links e meta (current_page, last_page, per_page, total). /api/messages responde com statusCode, data e meta (page, per_page, total, last_page).
Uma conversa é, em vez disso, paginada por cursor: GET /api/contacts/{uuid}/messages e GET /api/conversations/{contact_uuid} respondem do mais recente para o mais antigo com next_before; passe-o como before para obter as mensagens mais antigas.
Enviar um modelo
Um envio de modelo tem de levar exatamente tantos parâmetros quantos os marcadores do modelo aprovado; a Meta recusa uma discrepância com o erro 132000.
GET /api/templates/{uuid} devolve example_payload: um corpo completo para POST /api/send/template com o número certo de parâmetros para o cabeçalho, o corpo e os botões URL - substitua os valores e envie-o.
POST /api/templates submete um modelo à Meta a partir de uma forma JSON plana e responde com o motivo da Meta quando é recusado; POST /api/templates/sync obtém os modelos da Meta após uma alteração no Meta Business Manager.
GET https://whapier.com/api/templates/{{uuid}}
{"data": {"name": "order_update", "variables": {"header": 0, "body": 1, "buttons": 0}, "example_payload": {"phone": "+40721000001", "template": {"name": "order_update", "language": {"code": "en"}, "components": [{"type": "body", "parameters": [{"type": "text", "text": "Ana"}]}]}}}}
Webhooks
Os webhooks de saída configuram-se em Ferramentas de programador > Webhooks ou pela API (POST /api/webhooks): um URL https e os eventos a receber. O segredo de assinatura é gerado por nós e mostrado uma só vez. Cada entrega é um POST com um corpo JSON que leva event e data.
O cabeçalho X-Whapier-Signature é "sha256=" seguido do HMAC-SHA256 do corpo bruto do pedido com esse segredo, em hexadecimal. Volte a calculá-lo sobre os bytes que recebeu e compare antes de confiar no payload.
Responda 2xx em 15 segundos. Uma entrega que falha é repetida mais duas vezes, após 60 segundos e após 5 minutos; à terceira falha o evento é descartado.
Os eventos: message.received e message.sent; message.status quando a Meta reporta uma mensagem como delivered, read ou failed (com a falha e a campanha de onde veio); campaign.finished com as contagens finais; ticket.created e ticket.closed; contact.opted_out e contact.opted_in; contact, group e autoreply created, updated e deleted; template.status.update, template.quality.update e account.update tal como a Meta os envia. GET /api/webhooks/events lista-os com uma descrição e POST /api/webhooks/{uuid}/test entrega um exemplo.
X-Whapier-Signature: sha256=5d41402abc4b2a76b9719d911017c592...
{"event": "message.status", "data": {"uuid": "64968a32-fdd9-4c1d-8941-b8e538036616", "wam_id": "wamid.HBgM...", "status": "delivered", "timestamp": "2026-10-05T09:30:00+00:00", "failure": null, "contact": {"uuid": "81a2d165-41e2-43f2-847e-d69e08cba0e0", "phone": "+40721000001"}, "campaign": null}}
{"event": "campaign.finished", "data": {"uuid": "3f1c2d0e-5b7a-4c8d-9e0f-1a2b3c4d5e6f", "name": "October offers", "status": "completed", "counts": {"contacts": 120, "sent": 118, "delivered": 110, "read": 64, "failed": 2}, "finished_at": "2026-10-05T09:30:00+00:00"}}
message.received
message.sent
message.status
message.status.update
contact.created
contact.updated
contact.deleted
contact.opted_out
contact.opted_in
group.created
group.updated
group.deleted
autoreply.created
autoreply.updated
autoreply.deleted
campaign.finished
ticket.created
ticket.closed
template.status.update
template.quality.update
account.update
Versões: v1 e v2
/api (versão 1) continua suportado tal como está. /api/v2 serve os mesmos endpoints, payloads e campos com uma diferença: o estado HTTP transporta o resultado.
Na v2, uma recusa do WhatsApp num envio é um HTTP 422 cujo corpo tem statusCode 422, a message, error (code, message e type do WhatsApp) e data (a resposta da v1), em vez de um 200 com data.success false. Sempre que o statusCode num corpo difere do estado HTTP, o estado HTTP segue o statusCode.
Tudo o resto - autenticação, âmbitos, limite de pedidos, idempotência, datas, paginação - é idêntico, e a mesma chave funciona em ambas.
POST https://whapier.com/api/v2/send
{"statusCode": 422, "message": "Template name does not exist", "error": {"code": 132001, "message": "Template name does not exist", "type": "OAuthException"}, "data": {"success": false, "message": "Template name does not exist", "data": {"error": {"code": 132001}}}}
Verificação
GET
/api/verify
Verificar a chave de API
# Confirma que o token Bearer é válido e que a subscrição da organização está ativa, antes de chamar outros endpoints. # HTTP 200: token válido. 401: token em falta/inválido. 403: subscrição inativa. curl -X GET \ https://whapier.com/api/verify \ -H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \ -H 'Accept: application/json'
Contactos
GET
/api/contacts
Obter a lista de contactos
# Parâmetros opcionais: ?page=1&per_page=10 (per_page no máximo 100). # Do mais recente para o mais antigo. Resposta: data (objetos de contacto), links e meta (current_page, last_page, per_page, total). # Um contacto: id, uuid, phone, first_name, last_name, email, address, metadata, groups (uuid, name), source, opted_in_at, opted_out_at, created_at, updated_at. # Filtros de pesquisa, combinados com AND: phone (qualquer formato que o país da organização consiga ler; 400 quando não é um número), email (exato, sem distinguir maiúsculas), q (2 a 128 caracteres, procurado no nome, email e número), group (o uuid de um grupo de contactos; 400 quando é desconhecido), opted_out (true | false), updated_since (uma data, UTC), source (api, manual, import, entry point...). curl -X GET \ "https://whapier.com/api/contacts?page=1&per_page=10" \ -H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \ -H 'Accept: application/json'
GET
/api/contacts/{uuid}
Obter um contacto
# O objeto contacto de Obter a lista de contactos mais unread_messages, last_message_at e ticket (status, assigned_to: name, email).
# ticket é null enquanto o ticketing está desligado em Definições > Tickets, ou quando a conversa ainda não tem ticket. 404 quando o uuid é desconhecido, foi eliminado ou pertence a outro espaço de trabalho.
curl -X GET \
https://whapier.com/api/contacts/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
POST
/api/contacts
Adicionar contacto
# Campos do corpo JSON:
# phone (obrigatório) — número internacional; validado e guardado em E.164. Tem de ser único por organização (400 se estiver duplicado).
# first_name, last_name, email (opcionais) — omita-os, ou envie null ou "", para contactos sem nome.
# street, city, state, zip, country (opcionais) — guardados no JSON de address.
# metadata (opcional) — qualquer valor serializável em JSON.
# group (opcional) — array de strings com UUIDs de grupos de contactos.
# marketing_opt_in (opcional, booleano) — true regista o consentimento de marketing no contacto (histórico de consentimento RGPD, source: api); false regista um opt-out. Omita-o para deixar o consentimento inalterado.
# Respostas: 200 sucesso { statusCode, id, message }; 400 erro de validação; 403 subscrição inativa ou limite de contactos atingido.
# Aceita um cabeçalho Idempotency-Key (consulte Antes de começar).
curl -X POST \
https://whapier.com/api/contacts \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"phone": "+40721000001",
"first_name": "Ana",
"last_name": "Pop",
"email": "ana@example.com",
"group": [
"d746e4c5-db24-4fb2-be03-590421344d69"
],
"marketing_opt_in": true
}'
POST
/api/contacts/bulk
Criar ou atualizar contactos em massa
# contacts (obrigatório, 1 a 500 objetos) com os campos de Adicionar contacto por linha. Uma linha cujo phone já existe no espaço de trabalho é atualizada com os campos presentes (como faz Editar contacto); um número novo é criado.
# Cada linha é independente: uma linha errada falha sozinha e as outras passam. Resposta: { statusCode, created, updated, failed: [ { index, phone, errors } ], limit_reached, message }.
# A criação para no limite de contactos do plano: limit_reached fica true e as linhas que não couberam são listadas em failed. As atualizações nunca contam para o limite. Aceita um cabeçalho Idempotency-Key.
curl -X POST \
https://whapier.com/api/contacts/bulk \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"contacts": [
{
"phone": "+40721000001",
"first_name": "Ana",
"last_name": "Pop",
"email": "ana@example.com"
},
{
"phone": "0721 000 002",
"first_name": "Ion",
"group": [
"d746e4c5-db24-4fb2-be03-590421344d69"
]
},
{
"phone": "not-a-phone",
"first_name": "Nobody"
}
]
}'
PUT
/api/contacts/{uuid}
Editar contacto
# Os mesmos campos JSON de Adicionar contacto. O {uuid} do caminho é o id do contacto devolvido na criação.
# phone é opcional numa atualização; se o alterar, o novo número não pode pertencer a outro contacto (400 duplicado).
# É permitido atualizar com o mesmo phone deste contacto.
# Os campos que omitir mantêm o valor; envie um campo como null ou "" para o limpar. As chaves de metadata que enviar são fundidas com as já guardadas; as restantes mantêm-se.
# marketing_opt_in (opcional, booleano) — true regista o consentimento de marketing (source: api), false regista um opt-out; se for omitido, o consentimento fica inalterado.
# 404 quando o uuid é desconhecido, foi eliminado ou pertence a outro espaço de trabalho.
curl -X PUT \
https://whapier.com/api/contacts/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"first_name": "Ana",
"last_name": "Popescu",
"metadata": {
"plan": "platinum"
}
}'
DELETE
/api/contacts/{uuid}
Eliminar contacto
# Faz um soft delete do contacto; sai de imediato de todas as listas. 404 quando o uuid é desconhecido ou já foi eliminado.
# Resposta: { statusCode, id, message }.
curl -X DELETE \
https://whapier.com/api/contacts/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
Grupos de contactos
GET
/api/contact-groups
Obter a lista de grupos de contactos
# Parâmetros opcionais: ?page=1&per_page=10 (per_page no máximo 100). # Cada grupo: uuid, name, contacts_count (membros ativos), created_at, updated_at. curl -X GET \ "https://whapier.com/api/contact-groups?page=1&per_page=10" \ -H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \ -H 'Accept: application/json'
POST
/api/contact-groups
Adicionar grupo de contactos
# name (obrigatório) tem de ser único entre os grupos da organização (400 se já existir).
# Resposta: { statusCode, id, message }. Aceita um cabeçalho Idempotency-Key.
curl -X POST \
https://whapier.com/api/contact-groups \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"name": "Lead 5"
}'
PUT
/api/contact-groups/{uuid}
Editar grupo de contactos
# O mesmo corpo de Adicionar grupo de contactos. 404 para um uuid desconhecido.
curl -X PUT \
https://whapier.com/api/contact-groups/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"name": "Lead 5"
}'
DELETE
/api/contact-groups/{uuid}
Eliminar grupo de contactos
# Remove o grupo e as suas associações; os contactos em si são mantidos. 404 para um uuid desconhecido.
curl -X DELETE \
https://whapier.com/api/contact-groups/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
Respostas automáticas
GET
/api/canned-replies
Obter a lista de respostas automáticas
# Parâmetros opcionais: ?page=1&per_page=10 (per_page no máximo 100). # Cada resposta: uuid, name, trigger, match_criteria, response_type, response (o texto, ou null para multimédia), file (name, url) ou null, created_at, updated_at. curl -X GET \ "https://whapier.com/api/canned-replies?page=1&per_page=10" \ -H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \ -H 'Accept: application/json'
POST
/api/canned-replies
Adicionar resposta automática
# Corpo: name e trigger (máx. 255), match_criteria (exact match | contains), response_type (text | image | audio), response.
# Para text, response é a resposta (máx. 4096). Para image ou audio envie multipart/form-data com o ficheiro como response (png/jpg até 5 MB; mp3/aac/ogg/amr/opus/m4a até 16 MB); sem ficheiro, o pedido é um 400.
# Resposta: { statusCode, id, message }. 403 quando o limite de respostas automáticas do plano é atingido. Aceita um cabeçalho Idempotency-Key.
curl -X POST \
https://whapier.com/api/canned-replies \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"name": "About Us",
"trigger": "what do you do?",
"match_criteria": "contains",
"response_type": "text",
"response": "We sell shoes"
}'
PUT
/api/canned-replies/{uuid}
Editar resposta automática
# Os mesmos campos de Adicionar resposta automática. Uma atualização sem ficheiro mantém o conteúdo multimédia já existente. 404 para um uuid desconhecido.
curl -X PUT \
https://whapier.com/api/canned-replies/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"name": "About Us",
"trigger": "what do you do?",
"match_criteria": "contains",
"response_type": "text",
"response": "We sell shoes and clothes"
}'
DELETE
/api/canned-replies/{uuid}
Eliminar resposta automática
# 404 para um uuid desconhecido. Resposta: { statusCode, id, message }.
curl -X DELETE \
https://whapier.com/api/canned-replies/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
Linhas de WhatsApp
GET
/api/whatsapp-connections
Listar ligações
# Devolve o uuid de cada linha (use-o como whatsapp_connection em /api/send). Sem ids internos da base de dados. # Cada linha: uuid, type, name, phone, display_phone_number e, para uma linha WhatsApp Business, verified_name e number_status. 403 quando não há nenhuma linha ligada. curl -X GET \ https://whapier.com/api/whatsapp-connections \ -H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \ -H 'Accept: application/json'
Mensagens
POST
/api/send
Enviar mensagem
# Opcional: whatsapp_connection (UUID obtido em GET /api/whatsapp-connections). Omita-o para usar a linha predefinida da organização.
# phone (obrigatório) — em qualquer formato; normalizado para E.164 com o país da organização. Um número novo passa a ser um contacto (first_name, last_name, email opcionais).
# message (obrigatório, máx. 4096); header e footer (opcionais, máx. 60); buttons (opcional, até 3 de { id, title }).
# As mensagens de texto livre precisam de uma janela de 24 horas aberta: 422 quando a última mensagem do cliente tem mais de um dia. 403: subscrição, limite do plano, quota diária do período de teste ou conta em análise.
# Resposta: 200 { statusCode, data: { success, data: { chat: { uuid, wam_id, status, type, created_at, contact } } } }. Uma recusa do WhatsApp é um 200 com data.success false e data.data.error em /api; um HTTP 422 em /api/v2.
# Aceita um cabeçalho Idempotency-Key.
curl -X POST \
https://whapier.com/api/send \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"phone": "+40721000001",
"message": "Hello Ana, how are you?",
"whatsapp_connection": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"header": "Example Shoes",
"footer": "Reply STOP to opt out",
"buttons": [
{
"id": "yes",
"title": "Fine"
},
{
"id": "no",
"title": "Not well"
}
]
}'
POST
/api/send/media
Enviar multimédia
# Opcional: whatsapp_connection (UUID obtido em GET /api/whatsapp-connections). Omita-o para usar a linha predefinida da organização.
# media_type (image | video | audio | document | sticker); media_url (https, num anfitrião público; verificado com um pedido HEAD contra os limites de tamanho e de tipo do WhatsApp - caso contrário, 400 com o motivo); caption (opcional, não para audio); file_name (obrigatório para document).
# As mesmas proteções e a mesma resposta de Enviar mensagem.
curl -X POST \
https://whapier.com/api/send/media \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"phone": "+40721000001",
"media_type": "image",
"media_url": "https://cdn.example.com/offers/october.jpg",
"caption": "Our October offers"
}'
POST
/api/send/template
Enviar mensagem de modelo
# Opcional: "whatsapp_connection": "<uuid>" para uma linha WABA específica (UUID obtido em GET /api/whatsapp-connections).
# template.name e template.language ("en" ou { "code": "en" }) são obrigatórios; components seguem a estrutura do próprio WhatsApp (header, body, parâmetros dos botões).
# Funciona fora da janela de 24 horas. A um contacto que fez opt-out (STOP) não é enviado um modelo MARKETING: 422. Os modelos de utilidade e de autenticação continuam a ser enviados.
# As mesmas proteções e a mesma resposta de Enviar mensagem.
curl -X POST \
https://whapier.com/api/send/template \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"phone": "+40721000001",
"template": {
"name": "order_update",
"language": {
"code": "en"
},
"components": [
{
"type": "header",
"parameters": [
{
"type": "text",
"text": "48213"
}
]
},
{
"type": "body",
"parameters": [
{
"type": "text",
"text": "Ana"
},
{
"type": "text",
"text": "48213"
},
{
"type": "date_time",
"date_time": {
"fallback_value": "October 7, 2026"
}
}
]
},
{
"type": "button",
"sub_type": "url",
"index": "0",
"parameters": [
{
"type": "text",
"text": "48213"
}
]
}
]
}
}'
POST
/api/send/location
Enviar localização
# latitude (-90 a 90) e longitude (-180 a 180) obrigatórios; name e address opcionais.
# As mesmas proteções e a mesma resposta de Enviar mensagem.
curl -X POST \
https://whapier.com/api/send/location \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"phone": "+40721000001",
"latitude": 46.77120000000000032969182939268648624420166015625,
"longitude": 23.623599999999999710098563809879124164581298828125,
"name": "Example Shoes",
"address": "Str. Memorandumului 12, Cluj-Napoca"
}'
POST
/api/send/contacts
Enviar cartões de contacto
# contacts (1 a 10 cartões) no formato contacts[] do WhatsApp: name.formatted_name obrigatório; phones[], emails[], addresses[], org opcionais.
# As mesmas proteções e a mesma resposta de Enviar mensagem.
curl -X POST \
https://whapier.com/api/send/contacts \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"phone": "+40721000001",
"contacts": [
{
"name": {
"formatted_name": "Example Shoes Support",
"first_name": "Support"
},
"phones": [
{
"phone": "+40700000000",
"type": "WORK"
}
],
"emails": [
{
"email": "support@example.com",
"type": "WORK"
}
]
}
]
}'
POST
/api/send/reaction
Enviar reação
# message_id (o wam_id da mensagem a que se reage) e emoji (obrigatório; "" remove a reação).
# As mesmas proteções e a mesma resposta de Enviar mensagem.
curl -X POST \
https://whapier.com/api/send/reaction \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"phone": "+40721000001",
"message_id": "wamid.HBgMNDA3MjEwMDAwMDEVAgARGBI5QkY2RkE3RDlCMjc2RjI2QkEA",
"emoji": "👍"
}'
POST
/api/send/location-request
Pedir localização
# message (obrigatório, máx. 1024): o texto mostrado por cima do botão "Enviar localização".
# As mesmas proteções e a mesma resposta de Enviar mensagem.
curl -X POST \
https://whapier.com/api/send/location-request \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"phone": "+40721000001",
"message": "Where should we deliver?"
}'
POST
/api/send/request-contact-info
Pedir dados de contacto
# message (obrigatório, máx. 1024): pede a um utilizador do WhatsApp identificado apenas por nome de utilizador que partilhe o seu número de telefone.
# As mesmas proteções e a mesma resposta de Enviar mensagem.
curl -X POST \
https://whapier.com/api/send/request-contact-info \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"phone": "+40721000001",
"message": "Could you share your number so we can call you back?"
}'
POST
/api/send/carousel
Enviar carrossel
# message (obrigatório, máx. 1024) e cards (2 a 10): header { type: image | video, link } obrigatório; body (máx. 160), url_button { text, url } e quick_replies (até 3 de { id, title }) opcionais.
# As mesmas proteções e a mesma resposta de Enviar mensagem.
curl -X POST \
https://whapier.com/api/send/carousel \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"phone": "+40721000001",
"message": "Our new arrivals",
"cards": [
{
"header": {
"type": "image",
"link": "https://cdn.example.com/shoes/1.jpg"
},
"body": "Runner, 89 EUR",
"url_button": {
"text": "See it",
"url": "https://example.com/shoes/1"
}
},
{
"header": {
"type": "image",
"link": "https://cdn.example.com/shoes/2.jpg"
},
"body": "Trail, 119 EUR",
"quick_replies": [
{
"id": "trail",
"title": "Tell me more"
}
]
}
]
}'
Fluxos
POST
/api/flows/{uuid}/start
Iniciar um fluxo
# contact (obrigatório): o uuid ou o phone do contacto (normalizado com o país da organização).
# 200 { statusCode, success: true, message }; 404 fluxo ou contacto desconhecido; 422 fluxo não publicado; 409 o contacto já está numa sessão de fluxo.
# Tudo o que o fluxo envia está sujeito à janela de 24 horas, salvo se usar nós de modelo.
curl -X POST \
https://whapier.com/api/flows/{{uuid}}/start \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"contact": "+40721000001"
}'
Campanhas
GET
/api/campaigns
Listar campanhas
# Opcional: ?page=1&per_page=10&search= # Cada campanha: uuid, name, status, scheduled_at, created_at, template (uuid, name, language, category, status), whatsapp_connection (uuid, name, type), audience (type: all | group | segment, uuid, name), counts (contacts, sent, delivered, read, failed). curl -X GET \ "https://whapier.com/api/campaigns?page=1&per_page=10" \ -H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \ -H 'Accept: application/json'
POST
/api/campaigns
Criar campanha (modelo WABA com variáveis)
# Use quando whatsapp_connection for uma linha WhatsApp Cloud (WABA) obtida em GET /api/whatsapp-connections.
#
# PRÉ-REQUISITOS
# - template: UUID de um registo de GET /api/templates (no âmbito da organização), NÃO a string com o nome público do modelo.
# - Faça corresponder o número de variáveis ao seu modelo aprovado: abra os metadados do modelo na interface ou na Meta — o BODY usa {{1}}, {{2}}, … por ordem.
# - Tem de fornecer um parâmetro de body para cada marcador do BODY, pela mesma ordem. Um número que não corresponda ao modelo aprovado é recusado à partida (422), e não pelo WhatsApp a seguir.
#
# NOTAS SOBRE OS CAMPOS
# - contacts: "all" ou o uuid de um grupo de contactos; ou segment: o uuid de um segmento guardado (um dos dois, não ambos). send_immediately: true, ou scheduled_at (uma data, lida como UTC).
# - header: objeto opcional; se for omitido equivale a { "format": "TEXT", "parameters": [] }.
# - body: use body.parameters[] para as variáveis. Formato API (recomendado): { "type": "text", "value": "literal for {{1}}" } por posição.
# Alternativa (estilo painel): { "selection": "static", "value": "..." } ou { "selection": "dynamic", "value": "first name" } (associa campos do contacto).
# - footer / buttons: opcionais; use [] ou {} se não forem usados. Os modelos com variáveis de URL/resposta rápida precisam de buttons[] com a mesma forma do formulário de campanha da aplicação web.
# - Cabeçalho multimédia (IMAGE|VIDEO|DOCUMENT): header.parameters[] com type (IMAGE|VIDEO|DOCUMENT), "selection": "link", "value": "https://..." (URL público; a API não consegue carregar ficheiros).
#
# RESPOSTA: 200 { "statusCode": 200, "uuid": "...", "message": "..." }. Consulte GET /api/campaigns/{uuid} para o relatório e GET /api/campaigns/{uuid}/logs para o estado por destinatário, ou subscreva o webhook campaign.finished.
# 403 quando o limite de campanhas do plano é atingido. Aceita um cabeçalho Idempotency-Key.
curl -X POST \
https://whapier.com/api/campaigns \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"name": "Billing reminder blast",
"whatsapp_connection": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"contacts": "all",
"send_immediately": true,
"template": "281a3383-985c-4084-bcb0-9ec523c952de",
"header": {
"format": "TEXT",
"parameters": []
},
"body": {
"parameters": [
{
"type": "text",
"value": "Ana"
},
{
"type": "text",
"value": "48213"
},
{
"type": "text",
"value": "7 October 2026"
}
]
},
"footer": {},
"buttons": []
}'
GET
/api/campaigns/{uuid}
Obter uma campanha com o seu relatório
# O objeto campanha de Listar campanhas mais report: counts (contacts, sent, delivered, read, failed, pending), failure_reasons (code, title, count - os dez mais frequentes), started_at, finished_at (null até a campanha terminar), paused_reason, paused_detail e paused_at (null a menos que o estado seja paused).
# paused_reason é user (pausada a partir do painel ou da API), admin, failing, failure_rate ou quality (pausada pela plataforma; paused_detail diz porquê). 404 para uma campanha desconhecida.
curl -X GET \
https://whapier.com/api/campaigns/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
POST
/api/campaigns/{uuid}/pause
Pausar uma campanha
# Sem corpo. Só uma campanha scheduled ou ongoing pode ser pausada: 409 caso contrário, com o estado em que a campanha está. Os registos ficam como estão e retomar volta a pegar neles.
# Resposta: { statusCode, status, message } - status é o novo estado da campanha. 404 para uma campanha desconhecida.
curl -X POST \
https://whapier.com/api/campaigns/{{uuid}}/pause \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{}'
POST
/api/campaigns/{uuid}/resume
Retomar uma campanha
# Sem corpo. Só uma campanha paused pode ser retomada: 409 caso contrário. Uma campanha pausada antes da sua hora volta a scheduled; uma pausada durante o envio volta a ongoing.
# Resposta: { statusCode, status, message }. 404 para uma campanha desconhecida.
curl -X POST \
https://whapier.com/api/campaigns/{{uuid}}/resume \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{}'
POST
/api/campaigns/{uuid}/cancel
Cancelar uma campanha
# Sem corpo. Uma campanha scheduled, ongoing ou paused pode ser cancelada: 409 caso contrário. O que não foi enviado fica por enviar; o relatório continua a mostrar quem foi alcançado.
# Resposta: { statusCode, status, message }. 404 para uma campanha desconhecida.
curl -X POST \
https://whapier.com/api/campaigns/{{uuid}}/cancel \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{}'
GET
/api/campaigns/{uuid}/logs
Registos da campanha
# Opcional: ?page=1&per_page=10&search= (pesquisa por nome/telefone do contacto).
# Cada linha: contact (uuid, phone, first_name, last_name), status, message (uuid, wam_id, status) ou null, error (code, title, reason) ou null, retry_count, created_at, updated_at. 404 para uma campanha desconhecida.
curl -X GET \
"https://whapier.com/api/campaigns/{{uuid}}/logs?page=1&per_page=10" \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
Modelos
GET
/api/templates
Listar modelos
# Parâmetros opcionais: ?page=1&per_page=10 (per_page no máximo 100). # Cada modelo: uuid, name, language, category, status, components (tal como o WhatsApp os aprovou), variables (header, body, buttons: quantos marcadores cada parte recebe), rejection (o motivo da rejeição, ou null), quality_score, updated_at. curl -X GET \ "https://whapier.com/api/templates?page=1&per_page=10" \ -H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \ -H 'Accept: application/json'
GET
/api/templates/{uuid}
Obter um modelo com um exemplo pronto a enviar
# O objeto modelo de Listar modelos mais example_payload: um corpo completo para POST /api/send/template com um parâmetro por marcador (os exemplos com que o modelo foi submetido, ou um valor que nomeia a posição), uma ligação para um cabeçalho multimédia e um sufixo para cada botão URL com variável.
# Parâmetro opcional: whatsapp_connection (o uuid de uma linha) quando o mesmo modelo existe em várias linhas. 404 para um uuid desconhecido.
curl -X GET \
https://whapier.com/api/templates/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
POST
/api/templates
Criar modelo
# name (letras minúsculas, dígitos e underscores), category (MARKETING | UTILITY) e language (um código de idioma da Meta como en ou pt_BR) são obrigatórios; whatsapp_connection (o uuid de uma linha WhatsApp Business) é opcional - caso contrário, a linha predefinida.
# header (opcional): { format: TEXT, text (máx. 60, um único {{1}} permitido), examples } ou { format: IMAGE | VIDEO | DOCUMENT, media_url: uma ligação https pública para um ficheiro de exemplo }.
# body.text (obrigatório, máx. 1024, marcadores {{1}}, {{2}}, ...) com body.examples, um por marcador; footer (opcional, máx. 60); buttons (opcional, até 10): { type: QUICK_REPLY | URL | PHONE_NUMBER | COPY_CODE, text, url, phone_number, example }.
# Resposta: 200 { statusCode, uuid, status, message } - status é PENDING até a Meta o rever (o webhook template.status.update avisa). 400 com o motivo da Meta quando a Meta o recusa; os modelos AUTHENTICATION ainda não podem ser submetidos pela API. Uma chave sandbox não pode submeter (403). Aceita um cabeçalho Idempotency-Key.
curl -X POST \
https://whapier.com/api/templates \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"name": "order_update",
"category": "UTILITY",
"language": "en",
"header": {
"format": "TEXT",
"text": "Order {{1}}",
"examples": [
"48213"
]
},
"body": {
"text": "Hi {{1}}, your order {{2}} ships on {{3}}.",
"examples": [
"Ana",
"48213",
"October 7"
]
},
"footer": "Example Shoes",
"buttons": [
{
"type": "URL",
"text": "Track",
"url": "https://example.com/track/{{1}}",
"example": "48213"
},
{
"type": "QUICK_REPLY",
"text": "Stop updates"
}
]
}'
POST
/api/templates/sync
Sincronizar modelos a partir da Meta
# Sem corpo. Obtém da Meta os modelos de cada linha WhatsApp Business, como faz a atualização do painel, para que um modelo alterado no Meta Business Manager apareça também aqui.
# Resposta: { statusCode, synced, message } - synced é o número de modelos adicionados ou alterados. Uma chave sandbox não pode sincronizar (403); 400 quando a Meta recusou o pedido.
curl -X POST \
https://whapier.com/api/templates/sync \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{}'
Webhooks
GET
/api/webhooks
Listar webhooks
# Cada linha: uuid, url, events, secret_preview (os últimos seis caracteres do segredo de assinatura), created_at, updated_at. O segredo completo é mostrado uma só vez, na resposta de Adicionar webhook. # 403 quando o módulo Webhooks não está incluído no plano. curl -X GET \ https://whapier.com/api/webhooks \ -H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \ -H 'Accept: application/json'
GET
/api/webhooks/events
Listar eventos
# Cada evento que um webhook pode receber: data (name, description). A página Webhooks do painel lê o mesmo catálogo.
# Uma entrega é { event, data }; a forma de data por evento está em Antes de começar > Webhooks, e POST /api/webhooks/{uuid}/test entrega um exemplo de qualquer um deles.
curl -X GET \
https://whapier.com/api/webhooks/events \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
POST
/api/webhooks
Adicionar webhook
# url (obrigatório, https, único por organização) e events (obrigatório, um ou mais nomes de GET /api/webhooks/events).
# Resposta: { statusCode, uuid, secret, message } - a única vez em que o segredo completo é devolvido; guarde-o para verificar X-Whapier-Signature. Aceita um cabeçalho Idempotency-Key.
curl -X POST \
https://whapier.com/api/webhooks \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"url": "https://example.com/hooks/whapier",
"events": [
"message.received",
"message.status",
"campaign.finished"
]
}'
PUT
/api/webhooks/{uuid}
Editar webhook
# Mesmo corpo que Adicionar webhook. A lista events substitui a guardada; o segredo mantém-se. 404 para um uuid desconhecido.
curl -X PUT \
https://whapier.com/api/webhooks/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"url": "https://example.com/hooks/whapier",
"events": [
"message.received",
"message.status"
]
}'
DELETE
/api/webhooks/{uuid}
Eliminar webhook
# Remove o endpoint e as suas subscrições; nada mais lhe é entregue. Resposta: { statusCode, uuid, message }. 404 para um uuid desconhecido.
curl -X DELETE \
https://whapier.com/api/webhooks/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
POST
/api/webhooks/{uuid}/test
Enviar um evento de teste
# event (obrigatório): um nome de GET /api/webhooks/events. O payload de exemplo é enviado por POST para o url como { event, data, test: true }, assinado com o segredo em X-Whapier-Signature.
# Resposta: { statusCode, event, delivered, http_status, message } - delivered é false com o estado com que o seu endpoint respondeu, ou http_status null quando não foi possível contactá-lo. 404 para um uuid desconhecido.
curl -X POST \
https://whapier.com/api/webhooks/{{uuid}}/test \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"event": "message.status"
}'
Estado das mensagens
GET
/api/messages
Listar mensagens
# Parâmetros opcionais: status (sent | delivered | read | failed | accepted | played), direction (inbound | outbound), since e until (datas, UTC), contact (o uuid de um contacto), campaign (o uuid de uma campanha: as mensagens que produziu), wam_id (uma mensagem pelo id WhatsApp), api_key (o uuid de uma chave, ou current: as mensagens enviadas com a chave que faz o pedido), page, per_page (predefinição 25, máx. 100).
# Resposta: { statusCode, data: [ message ], meta: { page, per_page, total, last_page } }. 404 quando contact, campaign ou api_key é desconhecido.
# Uma mensagem: uuid, wam_id, direction, status, type, content, created_at, delivered_at, read_at, failed_at, failure (code, title, reason, retryable) ou null, pricing (category, model, billable, amount, currency, country), api_key (uuid, name) ou null quando não foi enviada pela API, contact (uuid, phone, first_name, last_name).
# content por type - text: body, header, footer, buttons (type, text); template: name, language, body; image, video, audio, document, sticker: caption, media (type, url, filename); interactive e button: text, payload (o que o cliente carregou); location: latitude, longitude, name, address; contacts: contacts (name, phones); reaction: emoji, wam_id.
curl -X GET \
"https://whapier.com/api/messages?status=failed&per_page=25" \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
GET
/api/contacts/{uuid}/messages
Conversa com um contacto
# Os mesmos objetos mensagem de Listar mensagens, para um só contacto, do mais recente para o mais antigo. Parâmetros opcionais: per_page (predefinição 25, máx. 100), before (o uuid da mensagem mais antiga que já tem).
# Resposta: { statusCode, data: [ message ], meta: { per_page, has_more, next_before } } - passe next_before como before para obter as mensagens mais antigas. 404 para um contacto ou um cursor desconhecido.
curl -X GET \
"https://whapier.com/api/contacts/{{uuid}}/messages?per_page=25" \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
GET
/api/messages/{uuid}
Obter uma mensagem
# O mesmo objeto de mensagem mais history: uma lista de { status, timestamp, recorded_at }, com cada mudança de estado comunicada pelo WhatsApp. 404 para um uuid desconhecido.
curl -X GET \
https://whapier.com/api/messages/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
Utilização
GET
/api/usage
Plano e utilização
# Dados da resposta: plan (name, status, valid_until), limits (contacts, messages, campaigns: used, limit; limit null = ilimitado), trial_daily_messages (apenas contas em período de teste), messages_sent (today, last_7_days, last_30_days), estimated_cost (last_30_days: amount, currency), rate_limit (per_minute). curl -X GET \ https://whapier.com/api/usage \ -H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \ -H 'Accept: application/json'
Caixa de entrada
GET
/api/conversations/{contact_uuid}
Obter uma conversa
# Resposta data: contact (uuid, phone, first_name, last_name), ticketing (se Definições > Tickets está ligado), ticket (status, assigned_to: name, email; opened_at, waiting_since, resolved_at) ou null, messages (uuid, wam_id, direction, type, text, status, created_at - as 50 mais recentes, primeiro a mais nova), next_before.
# Parâmetro opcional: before (o uuid da mensagem mais antiga que tem) para as mensagens anteriores; 400 quando o cursor não é uma mensagem deste contacto. 404 para um contacto desconhecido.
curl -X GET \
https://whapier.com/api/conversations/{{uuid}} \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Accept: application/json'
POST
/api/conversations/{contact_uuid}/assign
Atribuir uma conversa
# user_email (obrigatório, pode ser null): o email de um membro ativo da organização; null retira a atribuição do ticket. Uma conversa sem ticket recebe um.
# Resposta: { statusCode, data: ticket, message } com o ticket tal como Obter uma conversa o mostra. 409 enquanto o ticketing está desligado; 422 quando nenhum membro ativo da organização tem esse email; 404 para um contacto desconhecido.
curl -X POST \
https://whapier.com/api/conversations/{{uuid}}/assign \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"user_email": "maria@example.com"
}'
POST
/api/conversations/{contact_uuid}/close
Fechar uma conversa
# Sem corpo. Resolve o ticket (status closed, resolved_at definido), como o botão da caixa de entrada. Resposta: { statusCode, data: ticket, message }.
# 409 enquanto o ticketing está desligado; 404 para um contacto desconhecido.
curl -X POST \
https://whapier.com/api/conversations/{{uuid}}/close \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{}'
POST
/api/conversations/{contact_uuid}/reopen
Reabrir uma conversa
# Sem corpo. Reabre um ticket fechado (status open, resolved_at limpo); um ticket aberto é devolvido tal como está. Resposta: { statusCode, data: ticket, message }.
# 409 enquanto o ticketing está desligado; 404 para um contacto desconhecido.
curl -X POST \
https://whapier.com/api/conversations/{{uuid}}/reopen \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{}'
POST
/api/conversations/{contact_uuid}/notes
Adicionar uma nota interna
# note (obrigatório, máx. 5000): visível para os agentes na conversa, nunca enviada ao contacto. Funciona com o ticketing ligado ou desligado.
# Resposta: { statusCode, uuid, created_at, message }. 404 para um contacto desconhecido. Aceita um cabeçalho Idempotency-Key.
curl -X POST \
https://whapier.com/api/conversations/{{uuid}}/notes \
-H 'Authorization: Bearer <YOUR_AUTHORIZATION_TOKEN>' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d '{
"note": "Customer called; wants the order delivered on Friday."
}'
Obtenha uma chave de API em dois minutos
Teste gratuito, sem cartão de crédito — o painel de programador está incluído em todos os planos.
Testar gratuitamente