Números para verificação, direto do seu código
A mesma loja, pelo seu bot: cote, compre e leia o código em três chamadas. O estorno automático e a proteção contra compra repetida valem igual.
Do zero ao primeiro código em três chamadas
Crie a conta, confirme o e-mail e gere a chave em Automações. Ela vai no cabeçalho X-API-Key de toda chamada.
- 1
Escolha e cote
Pegue o
slugemGET /servicese pergunte o preço de agora. A cotação traz oband, o código da faixa.GET /quote - 2
Compre
Mande o preço e a faixa da cotação, com uma
Idempotency-Keynova. Se a rede cair, repita a mesma: a loja não cobra duas vezes.POST /orders - 3
Leia o código
Consulte o pedido a cada 5 segundos. Sem SMS em 18 minutos, o valor volta sozinho ao saldo.
GET /orders/{order_id}
O fluxo inteiro, pronto para copiar:
# 1. Cote
curl "https://api.smsvex.com/api/v1/integration/quote?service_slug=whatsapp-wa" \
-H "X-API-Key: $SMSVEX_API_KEY"
# 2. Compre (Idempotency-Key nova a cada tentativa)
curl -X POST "https://api.smsvex.com/api/v1/integration/orders" \
-H "X-API-Key: $SMSVEX_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"service_slug":"whatsapp-wa","expected_price_cents":890,"band":"3f9a1c07b2e4d856"}'
# 3. Leia o código
curl "https://api.smsvex.com/api/v1/integration/orders/48213" \
-H "X-API-Key: $SMSVEX_API_KEY"import os, time, uuid, requests
API = "https://api.smsvex.com/api/v1/integration"
H = {"X-API-Key": os.environ["SMSVEX_API_KEY"]}
# 1. Cote: o preço de agora e o código da faixa
cota = requests.get(f"{API}/quote", params={"service_slug": "whatsapp-wa"}, headers=H).json()
# 2. Compre com uma Idempotency-Key nova (repita a MESMA se a rede cair)
compra = requests.post(f"{API}/orders", headers={**H, "Idempotency-Key": str(uuid.uuid4())},
json={"service_slug": "whatsapp-wa",
"expected_price_cents": cota["price_cents"], "band": cota["band"]}).json()
pedido = compra["orders"][0]
print("Número:", pedido["phone"])
# 3. Leia o código
while True:
p = requests.get(f"{API}/orders/{pedido['id']}", headers=H).json()
if p["codes"]:
print("Código:", p["codes"][-1]); break
time.sleep(5)import { randomUUID } from "node:crypto";
const API = "https://api.smsvex.com/api/v1/integration";
const H = { "X-API-Key": process.env.SMSVEX_API_KEY };
// 1. Cote
const cota = await (await fetch(`${API}/quote?service_slug=whatsapp-wa`, { headers: H })).json();
// 2. Compre, com uma Idempotency-Key nova
const compra = await (await fetch(`${API}/orders`, {
method: "POST",
headers: { ...H, "Content-Type": "application/json", "Idempotency-Key": randomUUID() },
body: JSON.stringify({ service_slug: "whatsapp-wa",
expected_price_cents: cota.price_cents, band: cota.band }),
})).json();
const pedido = compra.orders[0];
// 3. Leia o código
for (;;) {
const p = await (await fetch(`${API}/orders/${pedido.id}`, { headers: H })).json();
if (p.codes.length) { console.log("Código:", p.codes.at(-1)); break; }
await new Promise((r) => setTimeout(r, 5000));
}$api = "https://api.smsvex.com/api/v1/integration";
$h = ["X-API-Key: " . getenv("SMSVEX_API_KEY")];
// 1. Cote
$cota = json_decode(file_get_contents("$api/quote?service_slug=whatsapp-wa", false,
stream_context_create(["http" => ["header" => $h]])), true);
// 2. Compre, com uma Idempotency-Key nova
$corpo = json_encode(["service_slug" => "whatsapp-wa",
"expected_price_cents" => $cota["price_cents"], "band" => $cota["band"]]);
$compra = json_decode(file_get_contents("$api/orders", false, stream_context_create(["http" => [
"method" => "POST", "content" => $corpo,
"header" => array_merge($h, ["Content-Type: application/json",
"Idempotency-Key: " . bin2hex(random_bytes(16))])]])), true);Mostre as faixas de preço para quem usa o seu bot
O mesmo serviço sai por preços diferentes, e cada preço é um grupo diferente de números. O mais barato entrega na maioria das vezes, mas não sempre: quando um número não recebe o SMS, trocar de faixa costuma resolver. A cotação traz todas elas.
Como a loja mostra no painel exemplo
- R$ 0,4013.995 númerospadrão
- R$ 0,426.902 números
- R$ 1,871.968 números
- Comece pela padrão (
is_default): é a mais barata que tem números para a quantidade pedida. - Deixe o usuário trocar: mostre o preço e o estoque de cada faixa e compre com o
bandda escolhida. - Se o SMS não chegar, o valor volta sozinho; ofereça a próxima faixa na nova compra.
- Não guarde o
band: cote de novo antes de cada compra. Se a faixa acabar, a compra recusa comBAND_GONEe nada é cobrado.
Deixe a IA escrever a integração
Copie o pedido abaixo e cole na ferramenta que você usa. Ele já leva as regras que protegem o seu saldo: chave fora do código, nada de compra repetida, limite de gasto.
Na pasta do projeto, abra o Claude Code (claude) e cole:
Na pasta do projeto, abra o Codex (codex) e cole:
Abra o agente do Cursor (Ctrl+I) e cole:
Cole numa conversa nova do ChatGPT ou do Claude.ai. Se ele não abrir links, use também Copiar a documentação:
Integre a API da SMSVEX (números virtuais para receber SMS de verificação) neste projeto.
Leia o contrato completo em https://smsvex.com/llms.txt; a base é https://api.smsvex.com/api/v1/integration.
Se não conseguir abrir o link, pare e peça que eu cole a documentação em Markdown; não invente rotas nem campos.
Regras que não podem ser quebradas:
1. Leia SMSVEX_API_KEY do ambiente e envie em X-API-Key; nunca grave nem registre a chave.
2. Antes de programar, pergunte o teto total de números e de gasto em centavos para esta execução.
3. Faça GET /services, depois GET /quote com service_slug e quantity. A cotação traz todas as faixas em bands.
4. Use a faixa is_default, a menos que eu escolha outra; mostre as faixas (preço e estoque) para o usuário trocar.
No POST /orders, envie expected_price_cents = price_cents DA FAIXA escolhida, o band dela, service_slug e quantity.
5. Cada tentativa usa Idempotency-Key nova; em timeout de rede, repita a MESMA chave E o MESMO corpo.
6. Em IDEMPOTENCY_IN_PROGRESS, nunca use chave nova: liste os abertos e pare se não identificar a compra sem dúvida.
7. Decida sempre por error.code, nunca pela mensagem.
8. PRICE_CHANGED ou BAND_GONE: cote de novo; só tente outra vez com a minha regra e dentro dos tetos restantes.
9. INSUFFICIENT_BALANCE: pare e peça recarga. TOO_MANY_OPEN_ORDERS: pare e conclua ou cancele um aberto.
10. Um 200 pode ser parcial: conte orders e charged_cents; failures não autorizam repetir a quantity original.
11. Nunca ultrapasse os dois tetos acumulados, mesmo com lote parcial, erro, nova tentativa ou nova cotação.
12. Acompanhe com GET /orders?desfecho=aberto&per_page=100 a cada 5 s; em 429, espere o Retry-After.
13. Use sms_window_minutes de GET https://api.smsvex.com/api/v1/limits como prazo do SMS; nunca um número fixo.
14. Código recebido não é código aceito: conclua (POST /orders/{id}/confirm) só quando eu disser que funcionou.
15. Se o código não chegar ou não for mais necessário, cancele só depois do can_cancel_at do pedido.
Entregue listar_servicos, cotar, comprar, esperar_codigos, cancelar e concluir, um exemplo que respeite os
tetos e testes com HTTP simulado. Antes de editar, mostre o fluxo de compra, repetição e lote e espere a minha
confirmação. Não faça compra real nos testes nem durante o desenvolvimento.Leve para a sua ferramenta
As duas saem do mesmo código da loja: nunca ficam para trás da documentação.
As 9 rotas
Base: https://api.smsvex.com/api/v1/integration. Todo valor em dinheiro é em centavos, inteiro. Toda data é ISO 8601, em UTC.
GETVer o saldo
/balanceO saldo da conta dona da chave, em centavos.
Erros desta rota
UNAUTHORIZED401Chave ausente, errada ou desligada.ACCOUNT_DISABLED403A conta está desativada.EMAIL_NOT_VERIFIED403O e-mail da conta não foi confirmado.RATE_LIMITED429Mais de 120 chamadas no minuto.INTERNAL_ERROR500Erro inesperado na loja.
Resposta exemplo
{
"balance_cents": 12450
}Testar agora
chamada real com a sua chave · não cobra nada · a chave não é guardadaGETListar serviços
/servicesOs serviços à venda agora, com o preço a partir de. O slug é o que as outras rotas pedem.
Parâmetros
qtexto- Filtra por nome. Ex.: whats
Erros desta rota
UNAUTHORIZED401Chave ausente, errada ou desligada.ACCOUNT_DISABLED403A conta está desativada.EMAIL_NOT_VERIFIED403O e-mail da conta não foi confirmado.VALIDATION_ERROR422Algum campo veio fora do formato.RATE_LIMITED429Mais de 120 chamadas no minuto.INTERNAL_ERROR500Erro inesperado na loja.
Resposta exemplo
{
"services": [
{ "slug": "whatsapp-wa", "name": "Whatsapp", "country": "BR", "price_cents": 890 },
{ "slug": "mercado-cq", "name": "Mercado", "country": "BR", "price_cents": 40 },
...
]
}Testar agora
chamada real com a sua chave · não cobra nada · a chave não é guardadaGETCotar um serviço
/quoteTodas as faixas de preço do serviço agora, com estoque. Não cobra nem reserva nada.
Parâmetros
service_slugtextoobrigatório- O serviço, como aparece no catálogo. Ex.: whatsapp-wa
quantityinteiro- Quantos números. Padrão 1.
Erros desta rota
UNAUTHORIZED401Chave ausente, errada ou desligada.ACCOUNT_DISABLED403A conta está desativada.EMAIL_NOT_VERIFIED403O e-mail da conta não foi confirmado.NOT_FOUND404O serviço ou o pedido não existe nesta conta.BAND_GONE409A faixa da cotação acabou.TOO_MANY_OPEN_ORDERS409Limite de números abertos atingido.VALIDATION_ERROR422Algum campo veio fora do formato.RATE_LIMITED429Mais de 120 chamadas no minuto.INTERNAL_ERROR500Erro inesperado na loja.PROVIDER_ERROR502A rede de números falhou.SERVICE_UNAVAILABLE503O serviço está fora do ar agora.
Resposta exemplo
{
"service_slug": "mercado-cq",
"quantity": 1,
"price_cents": 40,
"band": "3f9a1c07b2e4d856",
"total_cents": 40,
"bands": [
{ "price_cents": 40, "band": "3f9a1c07b2e4d856", "stock": 13995, "is_default": true, "atende": true },
{ "price_cents": 42, "band": "a81d09c4e2f7b350", "stock": 6902, "is_default": false, "atende": true },
{ "price_cents": 187, "band": "5c2e7f10d9ab4468", "stock": 1968, "is_default": false, "atende": true }
]
}Testar agora
chamada real com a sua chave · não cobra nada · a chave não é guardadaPOSTComprar números
/ordersCobra o saldo e reserva o número. Mande o preço e a faixa que a cotação devolveu.
Cabeçalhos
Idempotency-Keyobrigatório- Um valor novo a cada tentativa de compra (8 a 100 caracteres). Repetir a mesma chave devolve a mesma resposta, sem comprar de novo.
Corpo (JSON)
service_slugtextoobrigatório- O mesmo da cotação.
quantityinteiro- Padrão 1.
expected_price_centsinteiroobrigatório- O price_cents da cotação. Se o preço mudou, a compra recusa.
bandtextoobrigatório- O band da cotação. Se a faixa acabou, a compra recusa; nunca troca de faixa sozinha.
Erros desta rota
UNAUTHORIZED401Chave ausente, errada ou desligada.INSUFFICIENT_BALANCE402Saldo insuficiente.ACCOUNT_DISABLED403A conta está desativada.EMAIL_NOT_VERIFIED403O e-mail da conta não foi confirmado.NOT_FOUND404O serviço ou o pedido não existe nesta conta.BAND_GONE409A faixa da cotação acabou.IDEMPOTENCY_IN_PROGRESS409A compra com essa chave ainda está em andamento.IDEMPOTENCY_KEY_REUSED409Essa Idempotency-Key já foi usada em outra compra.LOW_CONFIRMATION_RATE409Muitos números sem uso recente.PRICE_CHANGED409O preço mudou desde a cotação.TOO_MANY_OPEN_ORDERS409Limite de números abertos atingido.IDEMPOTENCY_KEY_REQUIRED422Faltou o cabeçalho Idempotency-Key.VALIDATION_ERROR422Algum campo veio fora do formato.RATE_LIMITED429Mais de 120 chamadas no minuto.INTERNAL_ERROR500Erro inesperado na loja.PROVIDER_ERROR502A rede de números falhou.PROVIDER_OUT_OF_FUNDS502Esta compra está indisponível na loja agora.SERVICE_UNAVAILABLE503O serviço está fora do ar agora.
Resposta exemplo
{
"batch_id": null,
"orders": [ { "id": 48213, "phone": "5511987654321", "status": "active", ... } ],
"failures": [],
"charged_cents": 890,
"refunded_cents": 0
}GETListar pedidos
/ordersOs pedidos da conta. Com desfecho=aberto, só os que ainda esperam ou já têm código.
Parâmetros
desfechotexto- aberto, com_codigo, esperando, recebido, expirado, estornado ou cancelado.
page / per_pageinteiro- Página e tamanho (até 100).
de / atedata- Início e fim do período, em AAAA-MM-DD, no horário de Brasília.
qtexto- Busca por número de telefone ou #pedido.
Erros desta rota
UNAUTHORIZED401Chave ausente, errada ou desligada.ACCOUNT_DISABLED403A conta está desativada.EMAIL_NOT_VERIFIED403O e-mail da conta não foi confirmado.VALIDATION_ERROR422Algum campo veio fora do formato.RATE_LIMITED429Mais de 120 chamadas no minuto.INTERNAL_ERROR500Erro inesperado na loja.
Resposta exemplo
{
"orders": [
{
"id": 48213,
"service_slug": "whatsapp-wa",
"phone": "5511987654321",
"status": "received",
"codes": ["482913"],
"expires_at": "2026-09-30T17:42:10+00:00"
}
],
"total": 1
}Testar agora
chamada real com a sua chave · não cobra nada · a chave não é guardadaGETVer um pedido
/orders/{order_id}Um pedido, com os códigos que chegaram e a hora de cada um.
Parâmetros
order_idinteiroobrigatório- O id do pedido.
Erros desta rota
UNAUTHORIZED401Chave ausente, errada ou desligada.ACCOUNT_DISABLED403A conta está desativada.EMAIL_NOT_VERIFIED403O e-mail da conta não foi confirmado.NOT_FOUND404O serviço ou o pedido não existe nesta conta.VALIDATION_ERROR422Algum campo veio fora do formato.RATE_LIMITED429Mais de 120 chamadas no minuto.INTERNAL_ERROR500Erro inesperado na loja.
Resposta exemplo
{
"id": 48213,
"status": "received",
"codes": ["482913"],
"code_times": ["2026-09-30T17:24:55+00:00"],
"can_retry": true
}Testar agora
chamada real com a sua chave · não cobra nada · a chave não é guardadaPOSTCancelar e estornar
/orders/{order_id}/cancelCancela um número sem código e devolve o valor ao saldo.
Parâmetros
order_idinteiroobrigatório- O id do pedido.
Erros desta rota
UNAUTHORIZED401Chave ausente, errada ou desligada.ACCOUNT_DISABLED403A conta está desativada.EMAIL_NOT_VERIFIED403O e-mail da conta não foi confirmado.NOT_FOUND404O serviço ou o pedido não existe nesta conta.ORDER_NOT_CANCELLABLE409Este pedido não pode mais ser cancelado.CANCEL_TOO_EARLY422Ainda não dá para cancelar.VALIDATION_ERROR422Algum campo veio fora do formato.RATE_LIMITED429Mais de 120 chamadas no minuto.INTERNAL_ERROR500Erro inesperado na loja.PROVIDER_ERROR502A rede de números falhou.SERVICE_UNAVAILABLE503O serviço está fora do ar agora.
Resposta exemplo
{ "id": 48213, "status": "cancelled", ... }POSTPedir outro SMS
/orders/{order_id}/retryGrátis. Pede outro código no mesmo número.
Parâmetros
order_idinteiroobrigatório- O id do pedido.
Erros desta rota
UNAUTHORIZED401Chave ausente, errada ou desligada.ACCOUNT_DISABLED403A conta está desativada.EMAIL_NOT_VERIFIED403O e-mail da conta não foi confirmado.NOT_FOUND404O serviço ou o pedido não existe nesta conta.ORDER_NOT_RETRIABLE409Este pedido não aceita outro SMS.RETRY_BEFORE_FIRST_CODE422Outro SMS só depois do primeiro código.RETRY_WINDOW_CLOSED422O prazo para pedir outro SMS acabou.VALIDATION_ERROR422Algum campo veio fora do formato.RATE_LIMITED429Mais de 120 chamadas no minuto.INTERNAL_ERROR500Erro inesperado na loja.PROVIDER_ERROR502A rede de números falhou.SERVICE_UNAVAILABLE503O serviço está fora do ar agora.
Resposta exemplo
{ "id": 48213, "status": "active", ... }POSTConcluir o pedido
/orders/{order_id}/confirmDiz que o código funcionou. Libera a vaga de número aberto.
Parâmetros
order_idinteiroobrigatório- O id do pedido.
Erros desta rota
UNAUTHORIZED401Chave ausente, errada ou desligada.ACCOUNT_DISABLED403A conta está desativada.EMAIL_NOT_VERIFIED403O e-mail da conta não foi confirmado.NOT_FOUND404O serviço ou o pedido não existe nesta conta.ORDER_NOT_CONFIRMABLE409Este pedido não pode ser concluído.VALIDATION_ERROR422Algum campo veio fora do formato.RATE_LIMITED429Mais de 120 chamadas no minuto.INTERNAL_ERROR500Erro inesperado na loja.
Resposta exemplo
{ "id": 48213, "status": "completed", ... }Decida pelo code, nunca pelo texto
Todo erro chega como {"error": {"code", "message"}}. O texto pode mudar; o code, não.
| code | HTTP | O que houve | O que fazer |
|---|---|---|---|
UNAUTHORIZED | 401 | Chave ausente, errada ou desligada. | Confira o cabeçalho X-API-Key. Se gerou outra chave, a anterior parou de valer. |
ACCOUNT_DISABLED | 403 | A conta está desativada. | Fale com o suporte. |
EMAIL_NOT_VERIFIED | 403 | O e-mail da conta não foi confirmado. | Confirme o e-mail pelo site. |
RATE_LIMITED | 429 | Mais de 120 chamadas no minuto. | Espere os segundos do cabeçalho Retry-After. |
VALIDATION_ERROR | 422 | Algum campo veio fora do formato. | Confira o tipo e o tamanho de cada campo desta rota. |
NOT_FOUND | 404 | O serviço ou o pedido não existe nesta conta. | Confira o slug ou o id. |
SERVICE_UNAVAILABLE | 503 | O serviço está fora do ar agora. | Tente de novo em alguns minutos. |
INTERNAL_ERROR | 500 | Erro inesperado na loja. | Numa consulta, tente de novo. Numa compra, não repita antes de conferir em GET /orders se ela entrou. |
INSUFFICIENT_BALANCE | 402 | Saldo insuficiente. | Recarregue pelo site e tente de novo. |
PRICE_CHANGED | 409 | O preço mudou desde a cotação. | Cote de novo e compre com o preço novo. |
BAND_GONE | 409 | A faixa da cotação acabou. | Cote de novo. A compra nunca troca de faixa sozinha. |
TOO_MANY_OPEN_ORDERS | 409 | Limite de números abertos atingido. | Conclua ou cancele algum antes de comprar. |
LOW_CONFIRMATION_RATE | 409 | Muitos números sem uso recente. | Conclua os pedidos em que o código funcionou. |
IDEMPOTENCY_KEY_REQUIRED | 422 | Faltou o cabeçalho Idempotency-Key. | Mande um valor novo a cada tentativa. |
IDEMPOTENCY_KEY_REUSED | 409 | Essa Idempotency-Key já foi usada em outra compra. | Gere outra para a compra nova. |
IDEMPOTENCY_IN_PROGRESS | 409 | A compra com essa chave ainda está em andamento. | Antes de repetir, confira em GET /orders se ela entrou. |
PROVIDER_ERROR | 502 | A rede de números falhou. | Nada foi cobrado. Tente de novo. |
PROVIDER_OUT_OF_FUNDS | 502 | Esta compra está indisponível na loja agora. | Nada foi cobrado. Tente de novo mais tarde. |
CANCEL_TOO_EARLY | 422 | Ainda não dá para cancelar. | Espere o tempo da mensagem. |
ORDER_NOT_CANCELLABLE | 409 | Este pedido não pode mais ser cancelado. | Ele já tem código ou já fechou. |
RETRY_BEFORE_FIRST_CODE | 422 | Outro SMS só depois do primeiro código. | Espere o primeiro chegar. |
RETRY_WINDOW_CLOSED | 422 | O prazo para pedir outro SMS acabou. | Compre um número novo. |
ORDER_NOT_RETRIABLE | 409 | Este pedido não aceita outro SMS. | Ele já fechou. |
ORDER_NOT_CONFIRMABLE | 409 | Este pedido não pode ser concluído. | Só pedido com código pode. |