Melhoria
Mudanca de contrato: um pedido pode chegar sem endereco de entrega
As lojas em breve poderao registrar vendas feitas fora do WhatsApp: na loja fisica ou por telefone. Quando o produto foi entregue em maos, o pedido nao tem endereco, eGET /v1/orders e GET /v1/orders/{order_id} o devolvem com address: null. Se a sua
integracao le address.full_address, verifique antes que address nao e nulo.Um pedido tambem pode chegar sem linhas (items: []): foi registrado apenas a partir
de um comprovante de pagamento ou de uma marcacao da loja, e ganha suas linhas depois com o
mesmo id. Se voce sincroniza pedidos, leia-o de novo antes de considera-lo final.Dois valores novos que ja podem aparecer:payment_terms:paid_pending_review— o cliente enviou o comprovante e a loja ainda nao o revisou. Trate como nao pago ate que mude.statusde produto nas respostas:unpublished. Criar ou editar um produto continua aceitando apenaspublished.
Nova funcionalidade
Um envio que a conta nao pode pagar agora responde 402
Os envios de WhatsApp sao pagos a partir de um saldo pre-pago. Ate agora, uma conta sem
saldo podia continuar enviando pela API e a divida aparecia depois, sem ninguem ter sido
avisado. A partir de hoje, POST /v1/template-messages responde 402 e nao envia
nada quando a conta nao pode pagar a mensagem.O type diz qual dos tres casos e:insufficient_funds— a conta ficou sem saldo para mensagens de saida.wallet_sends_paused— os envios foram cortados quando o saldo acabou.wallet_currency_mismatch— o saldo esta numa moeda que esta API nao consegue cotar. Tentar de novo nao muda nada; fale com a gente.
event_id novo: o que recebeu o 402 continua
livre, entao voce pode reenviar o mesmo evento depois de recarregar e nada e duplicado.Tentar de novo sem recarregar devolve o mesmo 402. Trate como as outras recusas de
conta: registre o type e nao fique tentando em loop.Isto nao muda nada enquanto sua conta nao estiver incluida na cobranca por saldo. Ate
la a API responde exatamente como antes.
Correção
Templates com variáveis por nome já podem ser enviados
Um template criado com marcadores nomeados —Hola {{name}}, …, que é o que o editor de
campanhas escreve ao vincular uma variável a um campo do contato — aparecia em
GET /v1/templates com required_variables: [], como se não tivesse variáveis, e qualquer
envio era aceito com 202 para o provedor rejeitar depois. Agora:- O catálogo publica as chaves reais.
required_variableslista posições (["1", "2"]) ou nomes (["name"]) conforme o template foi criado, e um novo camposendablemarca o template que mistura os dois estilos, que não pode ser enviado por esta via. variablesaceita as mesmas chaves.{"name": "Ronald"}sai como parâmetro nomeado.- Um envio que o provedor rejeitaria é rejeitado antes, com
422. Uma chave faltando, uma sobrando ou uma posição num template nomeado não produzem mais um202vazio; a mensagem nomeia as chaves que o template espera.
422 que antes se perdia no provedor.Nova funcionalidade
O carrinho abandonado agora se ve e se desliga pelo painel
Saber se os envios de um comercio estavam saindo obrigava a consultarevent_id por
event_id, e desliga-los nao tinha outra via alem de parar de chamar a API do ecommerce.
As duas coisas agora se resolvem no painel de carrinho abandonado:- Historico de envios. Lista os envios do comercio, do mais recente ao mais antigo,
com o estado de cada um, dentro da janela de retencao de 30 dias. Nao e mais preciso
saber de antemao qual
event_idprocurar. - Interruptor de ligar e desligar. O envio pode ser desligado e ligado de novo sem tocar na integracao. Desligar nao apaga nada: o historico continua la.
POST /v1/template-messages responde 200 com
"status": "discarded" e "status_detail": "disabled". Nao e um erro: a requisicao
funcionou e o envio esta desligado de proposito, igual ao que acontece numa conversa em
pausa. O estado fica guardado sob o seu event_id, entao
GET /v1/template-messages/{event_id} conta a mesma historia.O seu ecommerce nao precisa de nenhuma mudanca. Se voce ja aceita qualquer 2xx e
ramifica pelo status, um envio desligado entra por onde stale e paused ja entram.
Esse catalogo de motivos pode crescer: registre o valor e nao ramifique de forma exaustiva
por ele.Melhoria
Enviar nao espera mais 10 segundos
POST /v1/template-messages mantinha o request aberto por 10 segundos aguardando uma
confirmacao de entrega que nunca chegava por esse caminho: esgotava a espera inteira
e respondia in_progress. Esses dez segundos nao compravam nenhuma informacao. Agora a
resposta chega assim que o servico de envio pega a mensagem. Tres coisas mudam para voce:- Um envio aceito responde
202, nao200. Se a sua integracao trata so o200como sucesso, ela passaria a ler envios bons como falhas. Aceite qualquer2xx. O200fica para as respostas que nao produzem um envio novo: umevent_idrepetido e um envio descartado (stale,paused). - O estado de um envio novo passa a ser
accepted, naoin_progress. Significam a mesma coisa — “a caminho, ainda nao sabemos como terminou” — e o desfecho continua sendo consultado emGET /v1/template-messages/{event_id}, que e o unico caminho: nenhum webhook reporta o resultado de um envio.in_progresscontinua sendo um valor valido do contrato: envios feitos antes desta mudanca ainda o devolvem enquanto estiverem dentro da janela de retencao de 30 dias. - A modalidade de confirmacao rapida por conta acaba, porque agora e o comportamento de todos. Nao ha nada a solicitar nem a configurar.
Correcao
O estado de um envio agora diz como ele terminou
GET /v1/template-messages/{event_id} respondia in_progress para sempre. sent,
delivered e read estavam no contrato mas nunca chegavam, e failed so aparecia por
uma recusa de conta. Uma mensagem recusada pela Meta parecia igual a uma entregue.
Agora o estado e resolvido contra a mensagem real. Tres coisas mudam para voce:- Os quatro estados ja chegam. Se a sua integracao assumia que
in_progressera o fim do caminho, voce passara a versent,delivered,readefailed. Ramifique pelostatus. status_detailem umfailednao e uma lista fechada e pode estar ausente. Alem deaccount_not_eligibleeno_sender_number, agora pode trazersend_failedquando o envio nao chegou a se completar,send_cancelledquando foi cancelado antes de ser tentado, ouprovider_error_<codigo>com o codigo da propria Meta quando o provedor recusou a entrega com um — por exemploprovider_error_131049, o limite de frequencia de modelos de marketing. Esse catalogo muda sem nos avisar: nao o trate de forma exaustiva, registre o valor e caia para uma falha generica se nao reconhece-lo ou se vier vazio.updated_ate quando o registro do envio mudou pela ultima vez, nao quando voce consultou. Consultar ja nao o move, mas ele pode se mover sem que o estado mude, entao nao serve como marca d’agua: reconcilie peloevent_id.
Correcao
GET /v1/templates le o catalogo de onde os envios realmente saem
A lista vinha de uma copia que o trilho de envio desta API nao escreve. Podia mostrar
modelos que o envio depois recusava, e esconder os que voce podia mandar. Agora os dois
leem o mesmo catalogo. Tres coisas mudam para voce:languagenao pode mais vir vazio. Antes diziamos que, se o modelo nao tivesse idioma registrado, qualquer codigo passava na validacao. Esse caso acabou: o catalogo registra o idioma sempre, entao um idioma que nao bate e422, sem excecao. Se voce dependia dessa saida, mande o codigo que a lista devolve.categoryagora chega em minusculas —marketing, naoMARKETING. Ajuste se voce compara a string como esta.- Sua lista pode mudar de tamanho, ate ficar vazia. Os modelos vivem no catalogo do trilho de envio, preenchido quando sua conta sincroniza com o WhatsApp. Uma lista vazia significa que hoje todo envio e recusado — escreva para nos e sincronizamos.
Melhoria
Uma recusa de envio agora diz o que aconteceu
POST /v1/template-messages respondia 502 para situações bem diferentes: uma conta não
habilitada, uma conversa em pausa, um event_id reciclado. De fora todas pareciam
idênticas, e a documentação pedia para repetir mesmo quando nenhuma retentativa podia
mudar o resultado. Agora cada uma tem a sua própria resposta:- Conta não habilitada para enviar →
422com"type": "account_not_eligible"emdetail[0]. Não é transitório: fale conosco para habilitá-la. - Sem número remetente conectado →
422com"type": "no_sender_number". Conecte o número de WhatsApp da sua conta e repita. - Conversa em pausa →
200com"status": "discarded"e"status_detail": "paused". A requisição funcionou; o envio está desligado de propósito, porque um agente humano assumiu a conversa ou há um corte de faturamento. event_idjá atrelado a outra mensagem, ou fora da janela de idempotência →409com"type": "idempotency_conflict". Mande o evento com umevent_idnovo: repetir o mesmo devolve o mesmo409.
502 fica só para uma falha real do serviço interno de envio, essa sim vale repetir com
backoff limitado.Com isso, failed passa a ser alcançável: as duas recusas de conta ficam guardadas
sob o seu event_id, então GET /v1/template-messages/{event_id} conta a mesma história
que o envio. Uma recusa de entrega ainda não produz esse estado. E um efeito da
idempotência que vale ter em mente: reenviar o mesmo event_id depois de uma recusa de
conta responde 200 com "status": "failed" — é o estado guardado, não um envio novo.Correcao
O envio outbound agora e roteado por ambiente
POST /v1/template-messages devolve 502 para qualquer envio que passe na validacao: a
chamada interna vai para um servico que nao atende essa rota. Esta versao da a escrita o
proprio endereco, configuravel por ambiente. O envio comeca a funcionar quando esse
endereco e apontado, nao com esta publicacao.Uma coisa nao vai mudar quando ligar: o template enviado nao aparecera em
GET /v1/conversations/{id}/messages. O envio e essa lista sao servidos por
armazenamentos diferentes, entao reconcilie pelo seu proprio event_id, nao pela lista.A conexao com o banco tambem nao fica mais retida durante a espera do envio. Se voce
fazia rajadas de envios, podia ver lentidao ou erros em outros endpoints da API durante
essas rajadas; isso esta corrigido aqui.Nova funcionalidade
Lista de templates aprovados
Novo endpointGET /v1/templates: devolve os templates que a sua conta pode enviar
agora mesmo, com as variáveis que cada um espera. É o que faltava para montar um
POST /v1/template-messages sem adivinhar os valores.Cada template traz:name— o valor que vai emtemplate.name.language— o valor que vai emtemplate.language. Pode vir vazio: o template não tem idioma registrado, mas o envio ainda exige um código, então não repasse onull— o request responde422. Só nesse caso qualquer código passa a validação; se o template registra idioma e o seu não corresponde, também é422. O código viaja tal qual para o WhatsApp, então errar o idioma faz o envio falhar lá — e hoje isso não se vê daqui: o estado fica emin_progress.required_variables— as chaves que precisam estar emvariables."1"preenche{{1}}. Uma lista vazia significa que o template não leva variáveis.categoryedisplay_name— este último énulla menos que difira doname, para reconhecê-lo do seu lado. A chave sempre vem: teste o valor, não a presença.
422. E se a lista voltar vazia,
a sua conta ainda não tem nenhum template aprovado — cada envio vai responder 422 até
que tenha.Escopo necessário: outbound:read.Correcao
Correcao do contrato de Mensagens de Template
A pagina de carrinho abandonado documentavaPOST /v1/cart-abandonments, um contrato que
foi substituido durante o desenho e que nunca existiu. Ele foi substituido pelo
contrato real, na mesma URL.Se voce comecou a construir contra a versao anterior, estas sao as mudancas que afetam
voce:- O caminho e
POST /v1/template-messages, e o estado e consultado emGET /v1/template-messages/{event_id}. - O template viaja no request, como
template: {name, language}. A versao anterior dizia o contrario: que ficava fixado do nosso lado. template_variablesagora se chamavariables.first_name,last_nameesecond_last_namenao existem. Este endpoint nao cria nem atualiza o contato, e hoje nenhuma chamada publica faz isso: a API de Contatos e somente leitura.occurred_ate opcional. Se voce omitir, o aviso nunca e considerado vencido.- Novo campo opcional
metadata.use_casepara atribuir o envio a um caso de uso. - Escopos necessarios:
outbound:sendeoutbound:read.
502. E os estados sent, delivered, read e failed ainda nao sao
alcancaveis — eles estao no contrato para que a sua integracao ja os contemple.Nova funcionalidade
Conversas, contatos, perfil da empresa e contagem de pedidos
Quatro novos grupos de endpoints somente leitura:- Conversas: Lista as conversas do comercio (
GET /v1/conversations, com filtrosale_status) e as mensagens de uma conversa (GET /v1/conversations/{conversation_id}/messages). Ler mensagens pela API nunca as marca como lidas. - Contatos: Lista os contatos do comercio com suas tags, status de opt-in e metadata (
GET /v1/contacts). - Empresa: Perfil publico da empresa (
GET /v1/company). - Contagem de pedidos: Total de pedidos e detalhamento por status (
GET /v1/orders/counts).
conversations:read, contacts:read, company:read (a contagem usa orders:read).MelhoriaCorrecao
Comprovantes de pagamento, resumo da conversa e correcao de midia
- Comprovantes de pagamento: Novo campo
payment_receipt_urlsnas respostas de pedidos. Contem a lista de URLs das imagens de comprovantes de pagamento enviados pelo cliente (Yape, Plin, transferencia bancaria, etc.). Se houver varios comprovantes, todos sao incluidos. - Resumo da conversa: Novo campo
summary_conversationnas respostas de pedidos. Contem um resumo gerado por IA com os detalhes do pedido e preferencias do cliente, evitando ter que entrar na conversa. - Correcao de midia de variante: Criar uma imagem de variante sem o campo
titlenao retorna mais erro. O campo e opcional conforme documentado.
Nova funcionalidade
Webhooks, fusos horarios e SKU
- Webhooks: Receba eventos de pedidos em tempo real (
order.created,order.status_changed). CRUD completo em/v1/webhooks. Assinatura HMAC-SHA256 em cada entrega. - Fusos horarios: Todas as datas (
order_date,created_at) agora sao retornadas no fuso horario local do comerciante. HeaderX-Timezoneincluido em cada resposta. - SKU: Novo campo
skuem variantes de produtos e itens de pedidos. - Variant ID: Novo campo
variant_idem itens de pedidos.
Nova funcionalidade
Gestao completa de produtos
- Produtos: Criar, atualizar e excluir produtos (
POST,PATCH,DELETE /v1/products) - Variantes: CRUD completo de variantes por produto
- Opcoes e valores: Gestao de opcoes e seus valores por produto
- Midia: Upload, atualizacao e exclusao de midia por variante
- Categorias: Criar, atualizar, excluir categorias e atribui-las a produtos
- Catalogos: Listagem de catalogos disponiveis (
GET /v1/catalogs)
Lancamento
Lancamento da Business API
Primeira versao publica da YaVendio Business API.- Pedidos: Listagem e detalhe de pedidos (
GET /v1/orders,GET /v1/orders/{order_id}) - Produtos: Consulta de produtos (
GET /v1/products,GET /v1/products/{product_id}) - Autenticacao: API Keys com header
X-API-Key - Rate Limiting: Controle de taxa de requisicoes por API Key
- Paginacao: Paginacao baseada em cursor para todas as listagens

