Visão geral
O BridgesAgents reúne produtos, preços e estoque de lojas de qualquer segmento do varejo (supermercado, eletrônicos, farmácia, moda...) num formato pronto para agentes de IA de compra.
Há três formas de consultar o catálogo, todas com a mesma chave de agente:
- MCP, para agentes de IA (Claude, ChatGPT, agentes próprios): o agente descobre e chama as tools sozinho.
- API REST, para sistemas e integrações tradicionais.
- UCP (Universal Commerce Protocol), para agentes que já falam esse padrão.
Comece por aqui: crie uma conta de desenvolvedor, gere a chave de agente em Chaves de agente no painel e envie em toda consulta no header Authorization: Bearer abd_… (detalhes em Autenticação).
| Recurso | URL |
|---|---|
| Servidor MCP (Streamable HTTP) | https://api.bridgesagents.com/mcp |
| API REST | https://api.bridgesagents.com/api/v1 |
| Referência interativa (Swagger) | https://api.bridgesagents.com/swagger-ui.html |
Conceitos
| Conceito | O que é |
|---|---|
| Lojista | A empresa (CNPJ) que vende. |
| Loja | Unidade física de um lojista, com endereço, coordenada, como atende (retirada, entrega por raio ou faixas de CEP) e horário. Preço e estoque variam por loja. O cadastro é feito pelo lojista. |
| Produto | O item em si, igual em qualquer loja: nome, marca, categoria, GTIN/EAN e unidade. Não tem preço. |
| Oferta | Produto × loja: preço, preço promocional e estoque. É o que o agente compara para decidir onde comprar. |
Detalhes que o agente deve levar em conta:
effectivePriceé o preço a pagar: o promocional quando existe, senão o normal.updatedAtdiz quando preço e estoque foram atualizados.stale: truemarca oferta sem atualização há mais de 7 dias (o preço pode ter mudado); com mais de 30 dias ela não aparece para agentes.soldByWeightindica venda por peso (ex.: hortifruti): o preço é por kg e o valor final só é conhecido na separação.- Unidades (
unit):UN,KG,G,L,ML. requiresPrescription: medicamento que exige receita. O agente não deve concluir a compra; oriente o consumidor a apresentar a receita na farmácia.adult: true: produto para maiores de 18 (bebida alcoólica, tabaco). A BridgesAgents só marca; quem confirma a idade é o agente.inStoreOnly: true: vendido só no local (combustível). Não entra em carrinho e não tem retirada nem entrega: mostre o preço, a distância emapsUrl(rota até a loja). Para acompanhar o preço da gasolina, busque comradiusKm.storeVerified: a empresa da loja tem CNPJ ativo na Receita Federal.storeRatingestoreRatingCount: nota média (1 a 5) e quantas avaliações de quem comprou pelo BridgesAgents.kind:GOOD(produto físico),FUEL(combustível),SERVICE(serviço),BOOKABLE(viagem, reserva) ouDIGITAL(curso, gift card). SóGOODvai para carrinho; os outros se compram pelobuyUrlda loja.currencyé a moeda dos preços (ISO 4217, ex.:BRL).priceTypediz como ler o preço:FIXED(fechado),FROM(a partir de),PER_NIGHT(por noite),PER_PERSON(por pessoa).fulfillmentdiz como chega:DELIVERY,PICKUP,IN_STORE(no local),AT_CUSTOMER(a domicílio),BOOKING(reserva) ouDIGITAL. Serviço e reserva não têm estoque (stocknulo); digital pode ser ilimitado. Reserva e digital valem de qualquer lugar.- No produto:
taxonomyId(categoria da Google Product Taxonomy),mpn(código do fabricante) eattributes(dados do tipo:color,size,duration_minutes,max_guests...).
Localização do consumidor
Busca e ofertas aceitam a localização do consumidor. Com ela, só aparecem lojas que entregam ali ou que ficam perto para retirada (até 30 km), e cada oferta diz como a loja atende.
- Prefira
latitudeelongitude: são precisas. Só com opostalCode(CEP), a coordenada vem de um serviço de CEP e muitas vezes é apenas o centro da cidade; nesse caso a distância vem comdistanceApproximate: true. - A entrega vale se o consumidor estiver no raio da loja ou numa das faixas de CEP que ela atende. Faixas de CEP funcionam mesmo sem coordenada, então mande o CEP sempre que tiver.
Conectar via MCP
O servidor usa o transporte Streamable HTTP em https://api.bridgesagents.com/mcp.
Claude Code
claude mcp add --transport http bridgesagents https://api.bridgesagents.com/mcp \
--header "Authorization: Bearer abd_SUA_CHAVE"Clientes que só aceitam servidores locais (stdio)
Use o mcp-remote como ponte. Exemplo de configuração (Claude Desktop, Cursor e similares):
{
"mcpServers": {
"bridgesagents": {
"command": "npx",
"args": ["mcp-remote", "https://api.bridgesagents.com/mcp", "--header", "Authorization:Bearer ${BRIDGESAGENTS_KEY}"],
"env": { "BRIDGESAGENTS_KEY": "abd_SUA_CHAVE" }
}
}
}Testar sem agente
O MCP Inspector lista e executa as tools pelo navegador. Escolha Streamable HTTP, informe a URL acima e adicione o header Authorization com Bearer abd_….
Clientes com suporte a OAuth (como o Claude e o MCP Inspector) não precisam de header: no primeiro acesso recebem 401 com WWW-Authenticate, descobrem o servidor de autorização, se registram sozinhos e abrem a página em que o consumidor entra (ou cria a conta) e permite o acesso. Veja Autenticação.
npx @modelcontextprotocol/inspectorTools MCP
search_products
Busca produtos pelo nome ou marca, em qualquer segmento. Ignora acentos e maiúsculas, aceita começo de palavra (arro → arroz) e sinônimos, inclusive regionais (bateria → pilha, bolacha → biscoito, macaxeira → mandioca). Tolera erro de digitação (arros → arroz) e entende termos em inglês e espanhol (rice, frijoles → feijão, haircut → corte).
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| query | string | sim | Texto da busca, em português. Ex.: "fone bluetooth". |
| limit | número | não | Máximo de resultados, de 1 a 50. Padrão: 10. |
| postalCode | string | não | Código postal do consumidor (no Brasil, o CEP; cep também é aceito). Com localização, só produtos que alguma loja atende ali. Fora do Brasil, mande latitude e longitude. |
| country | string | não | País do consumidor, 2 letras (BR, US, PT). Padrão: BR. Fora do Brasil, o código postal vira coordenada aproximada (OpenStreetMap). |
| latitude, longitude | número | não | Coordenada do consumidor (mais precisa que o CEP). |
| radiusKm | número | não | Só lojas até esta distância do consumidor, em km (até 100). Exige localização. Ex.: postos num raio de 5 km. |
[
{
"id": "00000000-0000-0000-0000-0000000000b8",
"gtin": "7890000000103",
"name": "Amoxicilina 500mg 21 cápsulas",
"brand": "Marca F",
"category": "Medicamentos",
"unit": "UN",
"requiresPrescription": true,
"imageUrl": "https://img.example.com/amoxicilina.png"
}
]get_offers
Lista as ofertas de um produto por loja, da mais barata para a mais cara (empate: a mais perto).
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| productId | UUID | sim | id vindo de search_products. |
| postalCode | string | não | Código postal do consumidor (no Brasil, o CEP; cep também é aceito). |
| country | string | não | País do consumidor, 2 letras (BR, US, PT). Padrão: BR. Fora do Brasil, o código postal vira coordenada aproximada (OpenStreetMap). |
| latitude, longitude | número | não | Coordenada do consumidor. |
| radiusKm | número | não | Só lojas até esta distância do consumidor, em km (até 100). Exige localização. Ex.: postos num raio de 5 km. |
[
{
"storeId": "00000000-0000-0000-0000-0000000000a4",
"storeName": "Farmácia Exemplo Savassi",
"city": "Belo Horizonte",
"region": "MG",
"price": 32.90,
"promoPrice": null,
"effectivePrice": 32.90,
"stock": 20.000,
"inStock": true,
"soldByWeight": false,
"requiresPrescription": true,
"updatedAt": "2026-10-25T21:51:47Z",
"stale": false,
"distanceKm": 0.2,
"distanceApproximate": false,
"pickup": true,
"delivery": { "fee": 0.00, "etaMinutes": 40, "minOrder": null, "coveredBy": "radius" },
"openNow": true,
"buyUrl": "https://api.bridgesagents.com/r/00000000-0000-0000-0000-0000000000cb"
}
]| Campo | O que significa |
|---|---|
| distanceKm | Distância em linha reta até a loja. Nula sem coordenada de um dos lados. |
| pickup | Dá para retirar na loja (retirada habilitada e loja perto do consumidor). |
| delivery | Condições de entrega (taxa, prazo em minutos, pedido mínimo) se a loja entrega ali; null se não entrega. coveredBy: cep_range (certo), radius (coordenadas exatas) ou radius_approximate (calculado com a coordenada do CEP: pode não valer, confirme com a loja). Sem localização, mostra as condições com coveredBy null. |
| openNow | Se a loja está aberta agora, no fuso dela. Nulo se a loja não informou horário. |
| buyUrl | Link para o consumidor comprar direto na loja: leva ao WhatsApp da loja (com a mensagem pronta, com produto e preço) ou ao site dela. Nulo se a loja não informou canal de compra. Mostre ao consumidor quando ele escolher a oferta. |
create_cart
Monta um carrinho numa loja e devolve confirmUrl: o link que o consumidor abre para revisar, informar nome e WhatsApp (e endereço, na entrega) e confirmar. O agente não fecha a compra sozinho e não recebe dados pessoais. O pedido vai para o painel e para o e-mail da loja; o pagamento é com a loja. Se a loja cadastrou chave Pix, o link mostra QR Code e copia e cola com o valor do pedido.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| storeId | UUID | sim | Loja (de get_offers). Um carrinho é de uma loja só. |
| items | lista | sim | De 1 a 50 itens { productId, quantity }. Quantidade fracionada só em produto vendido por peso. |
| fulfillment | string | sim | Produto: pickup (retirar) ou delivery (entrega). Serviço: in_store ou at_customer (a domicílio). Reserva: booking. Digital: digital. Use o que a oferta aceita (fulfillment em get_offers). |
| postalCode | string | na entrega | Código postal do consumidor (CEP no Brasil); a loja precisa entregar nele. |
| note | string | não | Recado para a loja (aparece no pedido). |
| scheduledFor | string | no serviço | Data e hora pedidas, com fuso (ex.: 2026-11-05T14:00-03:00). Use um horário livre de check_availability; fora do expediente ou lotado é recusado. |
| checkIn / checkOut | string | na reserva | Datas AAAA-MM-DD. checkOut é obrigatório com preço por noite (a linha multiplica pelas noites). |
| guests | número | na reserva | Pessoas. Obrigatório com preço por pessoa (a linha multiplica pelos hóspedes). |
| externalReference | string | não | Seu id para este carrinho (conversa ou usuário no seu sistema), até 100 caracteres. Volta em get_cart, em Pedidos dos agentes e nos webhooks do desenvolvedor. |
{
"id": "f4e2add5-0103-4fc2-aebb-77dbabff2241",
"status": "OPEN",
"store": { "id": "00000000-0000-0000-0000-0000000000a4", "name": "Farmácia Exemplo Savassi", … },
"fulfillment": "PICKUP",
"items": [
{ "productId": "00000000-0000-0000-0000-0000000000b6", "name": "Protetor Solar FPS 50 200ml",
"unit": "UN", "quantity": 2, "unitPrice": 52.90, "lineTotal": 105.80 }
],
"subtotal": 105.80,
"deliveryFee": null,
"total": 105.80,
"expiresAt": "2026-10-27T02:39:54Z",
"confirmUrl": "https://bridgesagents.com/compras/c/abc_…",
"order": null
}Produto com receita não entra em carrinho. Se algum item tiver problema (sem estoque, quantidade, loja que não vende), nada é criado e a resposta lista cada problema. Na confirmação, preço e estoque são conferidos de novo: se o preço mudou, o consumidor vê o valor novo antes de confirmar.
check_availability
Agenda em tempo real, antes de create_cart. Serviço: slots com os horários livres dentro do horário da loja (a cada duration_minutes) e as vagas que sobram (free, quando a loja informa capacity); use um start como scheduledFor. Reserva: nights com cada noite e as vagas livres (free, quando a loja informa units; 0 = lotado). O carrinho recusa horário fora do expediente ou lotado e sugere os próximos livres.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| storeId | UUID | sim | Loja (de get_offers). |
| productId | UUID | sim | Serviço ou reserva (de search_products). |
| from | AAAA-MM-DD | não | Primeiro dia; hoje se vazio. |
| days | inteiro | não | Quantos dias olhar, de 1 a 31 (padrão 7). |
get_cart
Situação de um carrinho criado pela sua chave: OPEN, CONFIRMED (com o número e o status do pedido) ou EXPIRED. O link vale 24 horas. Enquanto o pedido é NEW, order.respondBy diz até quando a loja aceita (2 h; 24 h para reserva e digital, contando a partir da abertura da loja): sem resposta, ele é cancelado sozinho com o motivo A loja não respondeu a tempo.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| cartId | UUID | sim | id devolvido por create_cart. |
Próximas tools: quote_delivery e pagamento pelo agente.
UCP e ACP
O mesmo catálogo também sai nos formatos de comércio para agentes do Google e da OpenAI. Cada produto (o mesmo em qualquer loja, pelo GTIN) traz as ofertas de todas as lojas. A compra continua na loja: ainda não há checkout pelo agente.
UCP (Universal Commerce Protocol)
O perfil em https://api.bridgesagents.com/.well-known/ucp anuncia as capacidades dev.ucp.shopping.catalog.search e dev.ucp.shopping.catalog.lookup (versão 2026-08-25). Cada oferta de loja é uma variante: a loja vem em seller, o preço em centavos ({"amount": 2490, "currency": "BRL"}), url é o link de compra. Distância, retirada, entrega e horário ficam em metadata. Informe context.postal_code para ver só as lojas que atendem o consumidor.
POST/ucp/v1/catalog/search
Busca por texto, com filtros categories e price (min/max em centavos) e paginação por cursor.
curl -X POST "https://api.bridgesagents.com/ucp/v1/catalog/search" -H "Authorization: Bearer abd_SUA_CHAVE" \
-H "Content-Type: application/json" \
-d '{"query": "pilha aa", "context": {"postal_code": "30140-010"}, "pagination": {"limit": 5}}'POST/ucp/v1/catalog/lookup
Produtos por ids; os que não existem voltam em messages com not_found.
POST/ucp/v1/catalog/product
Um produto por id, com todas as ofertas.
ACP (Agentic Commerce Protocol, OpenAI)
Feed de produtos do ChatGPT: um JSON por linha, uma linha por oferta de loja, com price no formato 19.90 BRL e is_eligible_checkout: false. Ofertas sem marca, sem imagem ou sem canal de compra ficam de fora (o formato exige esses campos), assim como produtos com receita. O header X-BridgesAgents-Skipped diz quantas ficaram de fora.
O feed é de uso interno: o próprio BridgesAgents o gera em /feeds/acp/products.jsonl.gz e envia à OpenAI. Agentes não precisam baixá-lo; para consultar o catálogo, use MCP, REST ou UCP com a chave de agente.
Importar catálogo
O lojista envia a planilha que já usa, em Excel (.xlsx) ou CSV, pelo painel ou pela API. Importar de novo atualiza preço e estoque, sem duplicar produtos.
- A primeira linha é o cabeçalho. A ordem das colunas não importa, e colunas desconhecidas são ignoradas.
- Os nomes são comparados sem acento, maiúsculas ou pontuação:
Preço de Vendaepreco_vendasão a mesma coluna. - Números aceitam o formato brasileiro (
1.234,56,R$ 27,90) e também27.90. - CSV pode usar ponto e vírgula, vírgula ou tab, em UTF-8 ou no formato padrão do Excel em português.
- Linhas com problema não impedem as outras: o resultado lista cada uma com o número da linha e o motivo.
- Combustível (gasolina, etanol, diesel, GNV) é marcado sozinho como vendido só no local: sem carrinho, aparece pela distância até o posto. Armas, munição, explosivos, cigarro eletrônico e drogas são recusados.
- Limites: 5 MB e 10.000 linhas por arquivo.
| Coluna | Nomes aceitos | Obrigatória | Observação |
|---|---|---|---|
| Nome | nome, produto, descrição, item | sim | Até 300 caracteres. |
| Preço | preço, valor, preço de venda, valor unitário | sim | Maior que zero. |
| EAN | ean, gtin, código de barras | não | 8, 12, 13 ou 14 dígitos. É o que liga seu produto ao mesmo produto de outras lojas. |
| Marca | marca, fabricante | não | Sem EAN, nome + marca identificam o produto. |
| Categoria | categoria, departamento, seção | não | |
| Unidade | unidade, un, und | não | UN (padrão), KG, G, L ou ML. |
| Preço promocional | preço promocional, promoção, preço oferta | não | Menor que o preço. |
| Estoque | estoque, quantidade, qtd, saldo | não | Padrão 0. |
| Vendido por peso | vendido por peso, por peso, granel | não | sim/não. Sem a coluna, unidade KG conta como vendido por peso. |
| Exige receita | exige receita, receita, tarja, venda sob prescrição | não | sim/não, ou "tarja vermelha"/"tarja preta". Os agentes não concluem a compra desses produtos. |
| Maior de 18 | maior de 18, maiores de 18, 18, adulto | não | sim/não. Bebida alcoólica e tabaco são marcados sozinhos; o agente controla a idade. |
| Imagem | imagem, foto, url da imagem, image_link | não | Endereço https:// público da foto do produto. |
| Tipo de item | tipo de item, kind | não | produto, combustível, serviço, reserva ou digital. Padrão: produto. |
| Moeda | moeda, currency | não | Código de 3 letras (BRL, USD, EUR). Padrão: BRL. No formato do feed do Google, o preço pode vir com a moeda (27.90 BRL). |
| Tipo de preço | tipo de preço, price_type | não | fixo, a partir de, por noite ou por pessoa. Padrão: fixo. |
| Atendimento | atendimento, como chega, fulfillment | não | entrega, retirada, no local, a domicílio, reserva ou digital (vários separados por vírgula). Padrão: o do tipo. |
| MPN e SKU | mpn, código do fabricante / sku, código interno | não | Código do fabricante (identifica o item sem EAN, junto com a marca) e o código no seu sistema. |
| Categoria do Google | google_product_category, categoria google | não | Id ou caminho da Google Product Taxonomy (ex.: 2271 ou Apparel & Accessories > Clothing). |
| Atributos | atributo_<nome> (ex.: atributo_duration_minutes), cor, tamanho, voltagem | não | Dados do tipo: cor e tamanho do produto, duração do serviço, hóspedes da reserva. A planilha do feed do Google Merchant Center também é aceita (title, price, sale_price, image_link...). |
Cadastro de lojas
O lojista é responsável pelo cadastro de cada loja: endereço, localização, como atende e horário. É com isso que os agentes sabem se a loja entrega para o consumidor, se dá para retirar por perto e se está aberta. O painel mostra o que falta em cada loja.
- Coordenada: informe a exata (no Google Maps, botão direito sobre a loja e clique nos números). Em branco, usamos uma aproximada pelo CEP, que pode ser só o centro da cidade.
- Entrega: por raio (km a partir da loja), por faixas de CEP ou os dois. Taxa, prazo em minutos e pedido mínimo são por loja.
- Canal de compra: WhatsApp de pedidos e/ou site. É para onde o link “comprar nesta loja” (
buyUrl) leva o cliente. No site,{produto}na URL é trocado pelo nome do produto. - Horário: por dia da semana, no fuso da UF da loja. Dois turnos com vírgula,
24houfechado. Fechar depois da meia-noite (22:00-02:00) também vale.
Planilha de lojas (redes)
Em Lojas → Importar planilha, a rede cadastra e atualiza todas as lojas de uma vez. O código identifica cada loja: se existir, atualiza; se não, cria.
| Coluna | Nomes aceitos | Obrigatória | Exemplo |
|---|---|---|---|
| Código | código, código da loja, filial | sim | BH-SAVASSI |
| Nome | nome, loja, unidade | sim | Farmácia Centro |
| CEP / código postal | cep, código postal, zip | sim | 30140-010 |
| Endereço | rua/logradouro, número, complemento, bairro, cidade, UF | não* | Rua Pernambuco, 1200 |
| Coordenada | latitude, longitude | não | -19.937410 / -43.934170 |
| Atendimento | retirada, entrega | não | sim / não |
| Entrega | raio km, taxa de entrega, prazo (min), pedido mínimo | não | 4 · 6,90 · 45 · 30,00 |
| Faixas de CEP | faixas cep, ceps atendidos | não | 30100-000 a 30199-999; 30210-000 |
| Horário | seg, ter, qua, qui, sex, sab, dom | não | 08:00-12:00, 14:00-20:00 · 24h · fechado |
| Canal de compra | whatsapp, site | não | (31) 99999-0000 · https://minhaloja.com.br/busca?q={produto} |
| Chave Pix | chave_pix, pix | não | Só no Brasil: CPF, CNPJ, e-mail, celular ou chave aleatória. O consumidor paga pelo link do pedido. |
* Cidade e UF são completadas pelo CEP quando ficam em branco. Baixar planilha modelo de lojas
Conectar o Bling
Quem usa o Bling não precisa de planilha nem de programação: em Integrações, no painel, o administrador conecta a conta Bling, autoriza o BridgesAgents (só leitura de produtos, estoque e depósitos) e escolhe qual depósito abastece cada loja.
- Preço, foto, código de barras, marca e categoria vêm do cadastro do produto no Bling.
- O estoque de cada loja é a soma do saldo disponível dos depósitos ligados a ela.
- Mudanças de preço e estoque chegam em segundos; uma sincronização completa roda todo dia de madrugada e aparece em Importações com a fonte Bling.
- Produto inativado ou excluído no Bling fica com estoque zero.
- Produtos com variação (cor, tamanho) ainda não entram: por enquanto, envie esses pela planilha.
Conectar a Nuvemshop
Quem vende numa loja virtual Nuvemshop também não precisa de planilha: em Integrações, no painel, o administrador conecta a loja, autoriza o BridgesAgents (só leitura de produtos e estoque) e escolhe qual loja do BridgesAgents recebe o estoque de cada local da Nuvemshop (com uma loja só, isso é automático).
- Cada variação vira um item, com o nome do produto e os valores da variação (ex.: "Camiseta Básica – Azul / M").
- Preço, preço promocional, foto, código de barras (quando é um GTIN válido), marca e categoria vêm da Nuvemshop.
- Variação sem controle de estoque na Nuvemshop aparece como disponível, com 999 unidades.
- Mudanças nos produtos chegam em segundos; uma sincronização completa roda todo dia de madrugada e aparece em Importações com a fonte Nuvemshop.
- Produto oculto, fora da vitrine ou excluído na Nuvemshop fica com estoque zero. Variação sem preço ("consulte") não entra.
Webhooks de pedido
Para o pedido cair direto no sistema da loja (ERP, PDV, agenda, n8n, Zapier): em Integrações, a central ou o desenvolvedor da empresa cadastra um endereço https e escolhe a loja (ou todas) e os eventos. Os administradores recebem um e-mail a cada webhook novo.
order.created: o consumidor confirmou o pedido (o mesmo momento do e-mail para a loja).order.status_changed: a loja aceitou, deixou pronto, concluiu ou cancelou (comcancelReason).order.paid: a loja marcou o pedido como pago (ou desfez:paidAtvolta vazio).- Cada envio é um
POSTcom o pedido completo emdata.order: itens comgtineskuda loja, cliente, endereço, agenda da reserva ou do serviço, totais e moeda. Campos novos podem aparecer; nenhum é renomeado. - Os dados do cliente vão só para a loja do pedido. Para devolver o status, use
POST /api/v1/me/orders/{id}/statuscom a chave da loja. - Número do pedido: escolha no cadastro o que o seu sistema aceita. Só números:
"number": 1042. Letras e números:"number": "AB1042". O camporeference("AB1042", o mesmo identificador do Pix e do link do consumidor) vai sempre. - Cabeçalho de acesso (opcional): se o seu sistema exige um token fixo (
Authorization: Bearer …,X-Api-Key...), cadastre o nome e o valor: ele vai em todo envio, junto com a assinatura. O valor fica cifrado e o painel mostra só o final. - Conta de desenvolvedor: em Webhooks, o desenvolvedor do agente recebe os mesmos eventos dos pedidos feitos pelas chaves dele, com
data.cart(id,externalReference,agentKeyId) e o pedido sem dados pessoais do comprador (customeredeliveryAddressvazios). É assim que o bot avisa o usuário sem ficar consultandoget_cart.
Exemplo
POST https://seusistema.com.br/agentbridge/pedidos
Content-Type: application/json
X-BridgesAgents-Event: order.created
X-BridgesAgents-Event-Id: 6f1c0d2e-…
X-BridgesAgents-Delivery: 0b9a7c41-…
X-BridgesAgents-Signature: t=1793000000,v1=5d2c…
X-Api-Key: (o cabeçalho de acesso, se você cadastrou um)
{
"id": "6f1c0d2e-…",
"event": "order.created",
"createdAt": "2026-10-27T14:03:11Z",
"data": {
"order": {
"id": "…", "number": 1042, "reference": "AB1042", "status": "NEW",
"storeId": "…", "storeCode": "CENTRO", "storeName": "Exemplo Centro",
"fulfillment": "DELIVERY",
"customer": { "name": "Ana Souza", "phone": "+5511988887777", "email": "ana@exemplo.com", "note": null },
"deliveryAddress": { "postalCode": "01310100", "street": "Av. Paulista", "number": "1000", "complement": null,
"district": "Bela Vista", "city": "São Paulo", "region": "SP" },
"items": [
{ "productId": "…", "gtin": "7890000000011", "sku": "ARZ-5", "name": "Arroz Branco Tipo 1 5kg", "unit": "UN",
"quantity": 2, "unitPrice": 24.90, "multiplier": 1, "lineTotal": 49.80, "adult": false }
],
"subtotal": 49.80, "deliveryFee": 8.00, "total": 57.80, "currency": "BRL", "estimated": false,
"schedule": { "scheduledFor": null, "checkIn": null, "checkOut": null, "guests": null },
"paidAt": null, "cancelReason": null, "agentNote": null,
"createdAt": "2026-10-27T14:03:10Z", "updatedAt": "2026-10-27T14:03:10Z",
"payment": { "status": "PENDING", "method": "PIX" }
}
}
}Conferir a assinatura
Ao cadastrar, o painel mostra uma única vez o segredo (whsec_…). Cada envio traz X-BridgesAgents-Signature: t=<segundos>,v1=<hex>, em que v1 é o HMAC-SHA256, com o segredo, de t + "." + corpo (o corpo exatamente como chegou). Recuse se não bater ou se t tiver mais de 5 minutos.
// Node.js (Express): use o corpo cru, antes de qualquer JSON.parse
import crypto from "node:crypto";
app.post("/agentbridge/pedidos", express.raw({ type: "application/json" }), (req, res) => {
const header = req.get("X-BridgesAgents-Signature") ?? "";
const t = header.match(/t=(\d+)/)?.[1];
const v1 = header.match(/v1=([0-9a-f]+)/)?.[1] ?? "";
const expected = crypto.createHmac("sha256", process.env.BRIDGESAGENTS_WEBHOOK_SECRET)
.update(`${t}.${req.body}`).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
if (!fresh || v1.length !== expected.length
|| !crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected))) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body);
// Guarde event.id: se chegar de novo (nova tentativa ou reenvio), ignore
res.sendStatus(200);
});# Python (Flask)
import hashlib, hmac, os, re, time
from flask import Flask, request, abort
app = Flask(__name__)
@app.post("/agentbridge/pedidos")
def pedidos():
header = request.headers.get("X-BridgesAgents-Signature", "")
t = re.search(r"t=(\d+)", header)
v1 = re.search(r"v1=([0-9a-f]+)", header)
if not t or not v1 or abs(time.time() - int(t[1])) > 300:
abort(401)
body = request.get_data(as_text=True)
expected = hmac.new(os.environ["BRIDGESAGENTS_WEBHOOK_SECRET"].encode(), f"{t[1]}.{body}".encode(),
hashlib.sha256).hexdigest()
if not hmac.compare_digest(v1[1], expected):
abort(401)
event = request.get_json()
return "", 200Respostas, novas tentativas e reenvio
- Responda 2xx em até 10 segundos e processe depois, se for demorado. Redirecionamento não é seguido.
- Sem 2xx, tentamos de novo em 1 min, 5 min, 30 min, 2 h e 12 h. Esgotadas (cerca de 15 h), o webhook é pausado e os administradores recebem e-mail; os pedidos continuam no painel.
- O mesmo evento pode chegar mais de uma vez (nova tentativa ou reenvio): use
X-BridgesAgents-Event-Id(igual aoiddo corpo) para ignorar repetidos. A ordem não é garantida depois de uma falha: comparedata.order.updatedAt. - No painel ficam os últimos envios (30 dias), com o erro de cada um, e os botões Enviar teste (pedido fictício, evento
webhook.test), Reenviar, Pausar/Reativar e Trocar segredo.
Testar no sandbox
No sandbox você testa o fluxo inteiro do seu agente sem uma loja de verdade: as lojas, os produtos e os pedidos são fictícios, e você faz o papel da loja e do checkout de pagamento.
- Pelo painel: em Pedidos dos agentes, abra um pedido e use os botões para aceitar, marcar como pronto, concluir ou cancelar, e para avisar o pagamento (pago no Pix, cartão ou boleto, recusado, estornado, contestado).
- Pela API, com a chave de agente (para testes automatizados):
POST /api/v1/carts/{id}/sandbox/statuscom{"status": "ACCEPTED"}(ACCEPTED, READY, COMPLETED, CANCELLED) ePOST /api/v1/carts/{id}/sandbox/paymentcom{"status": "paid", "method": "pix"}(paid, refused, refunded, chargeback, pending; pix, card, boleto). - Cada simulação muda o pedido de verdade: o consumidor é avisado, os seus webhooks recebem
order.status_changedeorder.paid, e oget_cartmostraorder.status,order.paymentStatus,order.paymentMethodeorder.paidAt. - Só pedidos montados pelas suas chaves. Em produção essas rotas não existem: quem responde é a loja.
# Aceitar o pedido e avisar o pagamento aprovado (sandbox, com a chave de agente)
curl -X POST https://api.sandbox.bridgesagents.com/api/v1/carts/$CART_ID/sandbox/status \
-H "Authorization: Bearer $BRIDGESAGENTS_KEY" -H "Content-Type: application/json" \
-d '{"status": "ACCEPTED"}'
curl -X POST https://api.sandbox.bridgesagents.com/api/v1/carts/$CART_ID/sandbox/payment \
-H "Authorization: Bearer $BRIDGESAGENTS_KEY" -H "Content-Type: application/json" \
-d '{"status": "paid", "method": "pix"}'Ferramenta completa: risco e regiões
Contas de desenvolvedor podem ver o nível de risco dos pedidos que os seus agentes geraram (GET /api/v1/me/agent-orders/{cartId}/risk) e os números por região das lojas da rede (GET /api/v1/me/insights/regions), e buscar pedidos por região (GET /api/v1/me/insights/orders?q=04001, pelo começo do CEP ou pelo nome da cidade ou do bairro): produtos e categoria, pagamento, recusas e o motivo, e o contato (nome, e-mail, telefone) só de pedidos com consentimento: o operador do bot colhe o consentimento do comprador, conforme a cláusula do contrato com a BridgesAgents. O que aparece depende do que o contrato libera, campo a campo, e cada busca fica registrada. No sandbox já está tudo liberado; em produção, mediante contrato com a BridgesAgents.
Enviar catálogo por API
Para o sistema da loja (ERP, loja virtual, script) mandar preços e estoque automaticamente, sem planilha. Mesmas regras e mensagens da importação por planilha.
1. Gere a chave
Há dois tipos:
- Chave da empresa (
POST /api/v1/me/api-keys): vale para todas as lojas. Cada item informastoreCode, o código da loja no seu sistema. Ideal para redes. - Chave de uma loja (
POST /api/v1/stores/{storeId}/api-keys): tudo vai para aquela loja estoreCodeé ignorado.
No painel, em Chaves de API, ou pela API com a sessão do lojista (veja Autenticação). A chave inteira só aparece nessa resposta: guarde-a com segurança.
curl -X POST "https://api.bridgesagents.com/api/v1/stores/{storeId}/api-keys" \
-H "Authorization: Bearer abs_…" \
-H "Content-Type: application/json" -d '{"name": "ERP"}'{
"apiKey": { "id": "…", "name": "ERP", "keyPrefix": "abk_Xy12Ab34", "createdAt": "…", "lastUsedAt": null, "revokedAt": null },
"key": "abk_Xy12Ab34…"
}2. Envie os itens com a chave
A chave vai no header X-Api-Key. Com a chave da empresa, a loja de cada item vem do storeCode; com a chave de uma loja, é sempre aquela loja. Cada item cria ou atualiza a oferta da loja; itens que não forem enviados continuam como estão (para tirar de venda, envie estoque 0). Até 1.000 itens por requisição.
curl -X POST "https://api.bridgesagents.com/api/v1/catalog/items" \
-H "X-Api-Key: abk_…" -H "Content-Type: application/json" \
-d '{
"items": [
{ "storeCode": "BH-SAVASSI", "gtin": "7890000000066", "name": "Pilha Alcalina AA com 4", "price": 17.50, "stock": 60 },
{ "storeCode": "BH-PAMPULHA", "gtin": "7890000000103", "name": "Amoxicilina 500mg 21 cápsulas",
"price": 29.90, "stock": 8, "requiresPrescription": true }
]
}'| Campo | Tipo | Obrigatório | Observação |
|---|---|---|---|
| name | texto | sim | Até 300 caracteres. |
| price | número | sim | Maior que zero, com ponto decimal (17.50). |
| gtin | texto | não | EAN com 8, 12, 13 ou 14 dígitos. Liga o item ao mesmo produto de outras lojas. |
| brand | texto | não | Sem GTIN, nome + marca identificam o produto. |
| category | texto | não | |
| unit | texto | não | UN (padrão), KG, G, L ou ML. |
| promoPrice | número | não | Menor que price. |
| stock | número | não | Padrão 0. |
| soldByWeight | true/false | não | Sem o campo, unidade KG conta como vendido por peso. |
| requiresPrescription | true/false | não | Medicamento com receita. Os agentes não concluem a compra. |
| adult | true/false | não | Maiores de 18. Bebida alcoólica e tabaco já são marcados pelo nome e pela categoria. |
| storeCode | texto | com chave da empresa | Código da loja no seu sistema (cadastrado em Lojas). |
| kind | texto | não | GOOD, FUEL, SERVICE, BOOKABLE ou DIGITAL. Padrão: GOOD. |
| currency | texto | não | ISO 4217 (BRL, USD, EUR). Padrão: BRL. |
| priceType | texto | não | FIXED, FROM, PER_NIGHT ou PER_PERSON (cada tipo aceita alguns). |
| fulfillment | lista | não | DELIVERY, PICKUP, IN_STORE, AT_CUSTOMER, BOOKING, DIGITAL. Padrão: o do tipo. |
| mpn / sku | texto | não | Código do fabricante e código no seu sistema. |
| googleCategory | texto | não | Id ou caminho da Google Product Taxonomy. |
| attributes | objeto | não | Dados do tipo, ex.: {"duration_minutes": 60, "capacity": 2} (serviço: duração e atendimentos ao mesmo tempo) ou {"max_guests": 2, "check_in": "14:00", "units": 3} (reserva: unidades iguais por noite). |
| imageUrl | texto | não | Endereço https:// público da foto do produto. Vale a primeira informada para o produto. |
A resposta diz o que entrou. Itens com problema não impedem os outros e aparecem em errors com a posição em items (começando em 0):
{
"received": 2, "imported": 1, "failed": 1,
"productsCreated": 0, "offersCreated": 0, "offersUpdated": 1,
"errors": [ { "index": 1, "gtin": null, "name": "Banana Prata", "message": "Preço em branco." } ]
}Para trocar uma chave vazada, gere outra e revogue a antiga no painel (ou com DELETE /api/v1/stores/{storeId}/api-keys/{keyId}).
API REST
Respostas em JSON. Os campos de produto e oferta são os mesmos das tools MCP.
GET/api/v1/products?q={busca}&limit={1-50}&postalCode=&lat=&lng=
Busca produtos. limit é opcional (padrão 20); postalCode, lat e lng filtram pelas lojas que atendem o consumidor (veja Localização do consumidor).
curl -H "Authorization: Bearer abd_SUA_CHAVE" "https://api.bridgesagents.com/api/v1/products?q=pilha%20aa"GET/r/{offerId}
O buyUrl das ofertas: conta o clique e redireciona para o WhatsApp ou o site da loja.
GET/api/v1/products/{id}/offers
Ofertas do produto por loja, da mais barata para a mais cara.
curl -H "Authorization: Bearer abd_SUA_CHAVE" \
"https://api.bridgesagents.com/api/v1/products/00000000-0000-0000-0000-0000000000b7/offers?postalCode=30140-010"GET/api/v1/products/{id}/availability
Mesmo que a tool check_availability: ?storeId=...&from=AAAA-MM-DD&days=7.
POST/api/v1/carts
Mesmo que a tool create_cart. Responde 201 com o carrinho e confirmUrl; itens com problema voltam em problems (HTTP 400).
curl -X POST "https://api.bridgesagents.com/api/v1/carts" -H "Authorization: Bearer abd_SUA_CHAVE" \
-H "Content-Type: application/json" \
-d '{"storeId": "00000000-0000-0000-0000-0000000000a4", "fulfillment": "pickup",
"items": [{"productId": "00000000-0000-0000-0000-0000000000b6", "quantity": 2}]}'GET/api/v1/carts/{id}
Mesmo que a tool get_cart.
Com sessão do lojista (header Authorization: Bearer abs_…)
GET/api/v1/me
Lojista logado.
GET/api/v1/me/stores
Lojas do lojista logado, com o cadastro completo e o que falta em cada uma (pending).
POST/api/v1/me/stores
Cadastra uma loja. PUT /api/v1/me/stores/{id} atualiza.
POST/api/v1/me/stores/import
Planilha de lojas (multipart/form-data, campo file). Veja Cadastro de lojas.
GET/api/v1/me/offers?q=&storeId=&stale=&page=&size=
Ofertas das lojas que você enxerga (gerente: só as dele), por nome do produto: preço, estoque, quando foi atualizada, stale e hidden. q procura em nome, marca e código de barras; stale=true traz só as paradas há mais de 7 dias. Paginada (size até 100).
GET/api/v1/me/offers/freshness
Ofertas paradas por loja: total, sem atualização há mais de 7 dias (stale) e há mais de 30 (hidden, já fora dos agentes).
GET/api/v1/me/performance?days={1-90}
Desempenho das lojas que a pessoa enxerga: aparições para agentes, vezes com o menor preço e cliques no link de compra, por loja e por produto.
GET/api/v1/me/price-insights?days={1-90}&storeId=&limit=
Inteligência de preço: para cada produto seu, como o seu preço se compara ao de outras lojas da mesma cidade (sem identificar quais) e quantas vezes você deixou de ser o menor preço nas consultas dos agentes. days de 1 a 90.
GET/api/v1/me/agent-orders?status=&keyId=
Conta de desenvolvedor: carrinhos e pedidos das suas chaves de agente, sem dados do comprador (cartStatus OPEN, CONFIRMED ou EXPIRED; orderStatus, respondBy, paidAt, externalReference). status: open, confirmed, expired ou cancelled. GET .../summary?days=30 traz carrinhos, confirmados, conversão e pedidos que a loja não respondeu.
GET/api/v1/me/orders?status=&storeId=
Pedidos das lojas que você enxerga. status: novos, andamento, concluidos ou cancelados (sem ele, todos). GET .../summary traz quantos novos e em andamento; GET .../{id}, o pedido com dados do cliente.
POST/api/v1/me/orders/{id}/status
Muda o status: ACCEPTED, READY, COMPLETED ou CANCELLED (com reason, que o cliente vê). Só avança na ordem; o cliente é avisado por e-mail se informou um.
POST/api/v1/me/api-keys
Gera a chave da empresa (todas as lojas). GET lista e DELETE .../{keyId} revoga.
POST/api/v1/stores/{storeId}/catalog/import
Importa a planilha de uma loja sua. Envie como multipart/form-data no campo file.
curl -H "Authorization: Bearer abs_…" -F "file=@catalogo.xlsx" \
"https://api.bridgesagents.com/api/v1/stores/{storeId}/catalog/import"GET/api/v1/me/imports?problems={true|false}&limit={1-100}
Histórico de importações (planilha e API) das suas lojas, da mais recente para a mais antiga. problems=true traz só as com itens rejeitados ou recusadas.
GET/api/v1/me/imports/{id}
Uma importação, com os itens rejeitados (errors): linha da planilha ou posição em items, e o motivo.
Com chave de API da loja (header X-Api-Key: abk_…)
POST/api/v1/catalog/items
Envia itens em JSON. Veja Enviar catálogo por API.
POST/api/v1/stores/{storeId}/api-keys
Com sessão do lojista: gera uma chave para uma loja sua. GET no mesmo caminho lista as chaves (só o começo de cada uma) e DELETE .../api-keys/{keyId} revoga.
{
"rows": 120,
"imported": 118,
"failed": 2,
"productsCreated": 40,
"offersCreated": 100,
"offersUpdated": 18,
"ignoredColumns": ["Observações"],
"errors": [
{ "line": 7, "message": "Preço inválido: \"abc\"." },
{ "line": 31, "message": "Nome do produto em branco." }
]
}Para testar os endpoints direto no navegador, use a referência interativa (Swagger).
Erros e limites
| Situação | Resultado |
|---|---|
| Busca vazia | Lista vazia. |
| limit fora de 1 a 50 | Ajustado para o limite mais próximo. |
| Produto sem ofertas ou id inexistente | Lista vazia. |
| id que não é um UUID (REST) | HTTP 400. |
| Parâmetro q ausente (REST) | HTTP 400. |
| Importação: arquivo vazio, formato não suportado, sem colunas nome e preço ou mais de 10.000 linhas | HTTP 400. |
| Importação: arquivo acima de 5 MB | HTTP 413. |
| Consulta ao catálogo (REST, MCP ou UCP) sem chave de agente, ou com chave inválida ou revogada | HTTP 401. |
| Mais de 120 consultas por minuto com a mesma chave | HTTP 429, com Retry-After. |
| Sem sessão ou sessão expirada (rotas do painel) | HTTP 401. |
| Conta de lojista criando chave de agente, ou conta de desenvolvedor criando loja | HTTP 403. |
| Loja ou importação que não é sua (ou não existe) | HTTP 404. |
| Envio por API: sem X-Api-Key, chave inválida ou revogada | HTTP 401. |
| Busca: CEP inválido, só latitude ou só longitude, ou coordenada fora do Brasil | HTTP 400. |
| Cadastro de loja com dado inválido (CEP, UF, coordenada, horário, faixa de CEP) | HTTP 400, com o motivo. |
| Envio por API: JSON malformado, sem itens ou mais de 1.000 itens | HTTP 400. |
Erros vêm no formato application/problem+json (RFC 9457). O campo detail já traz uma mensagem em português que pode ser mostrada ao lojista.
Autenticação
| Quem | Como | Para quê |
|---|---|---|
| Agente (conta de desenvolvedor) | Chave de agente: Authorization: Bearer abd_… | Buscar produtos e ofertas: REST, MCP e UCP. Obrigatória. |
| Assistente de IA do consumidor | OAuth 2.1: Authorization: Bearer abo_… | Buscar produtos e ofertas em nome de um consumidor que conectou o assistente. Escopo catalog. |
| Lojista | Sessão: Authorization: Bearer abs_… | Painel, importar planilha, gerar chaves, ver o histórico. Só enxerga as próprias lojas. |
| Sistema do lojista | Chave da loja: X-Api-Key: abk_… | Enviar o catálogo em JSON para aquela loja. |
Chave de agente
Nenhuma consulta ao catálogo é anônima. Crie a conta de desenvolvedor (sem CNPJ) e gere as chaves em Chaves de agente, no painel. A chave aparece uma vez só; o banco guarda apenas o hash. Use uma chave por agente ou ambiente: se uma vazar, revogue só ela. O painel mostra quantas consultas cada chave fez por dia, e o limite é de 120 por minuto por chave.
curl -X POST "https://api.bridgesagents.com/api/v1/me/agent-keys" -H "Authorization: Bearer abs_…" \
-H "Content-Type: application/json" -d '{"name": "Agente em produção"}'
# → { "apiKey": { "id": "…", "keyPrefix": "abd_Xk3…" }, "key": "abd_…" } (só desta vez)Planos e franquia
Cada requisição autenticada com chave de agente conta uma consulta (busca, ofertas, carrinho ou chamada MCP). O plano Grátis inclui 10.000 consultas por mês; ao chegar nelas, a API responde 429 com a explicação em detail até o dia 1º do mês seguinte. Os planos pagos (Pro e Escala) não bloqueiam: o excedente é cobrado por bloco de 1.000 consultas na fatura do fim do mês. Avisamos por e-mail aos 80% e aos 100% da franquia, e o uso do mês aparece em Plano e cobrança, no painel. O sandbox não tem franquia.
Sandbox
Para testar sem atingir lojas de verdade, use o sandbox: site em https://sandbox.bridgesagents.com e API em https://api.sandbox.bridgesagents.com (MCP em /mcp). Ele tem a mesma versão da produção (toda mudança é publicada nos dois), mas banco próprio, com lojas e produtos de exemplo. Crie lá uma conta de desenvolvedor: as chaves começam com abd_test_ e não valem na produção (nem as de produção valem lá). Carrinhos e pedidos funcionam de ponta a ponta, só que nas lojas de exemplo; os e-mails chegam com [Sandbox] no assunto.
OAuth 2.1 (servidor MCP)
Seguimos a autorização da especificação MCP: metadados em /.well-known/oauth-protected-resource e /.well-known/oauth-authorization-server, registro dinâmico em POST /oauth/register (só clientes públicos), código com PKCE S256 obrigatório em /oauth/authorize e POST /oauth/token. O token de acesso (abo_) vale 1 hora e o de renovação (abr_) 30 dias, trocado a cada uso; reusar um token de renovação ou um código derruba a conexão. POST /oauth/revoke revoga. O consumidor vê e desconecta os apps em Minhas compras › Apps conectados.
Ficam públicos só a descoberta (/.well-known/ucp), esta documentação e o link de compra /r/…, que o consumidor abre.
Sessão do painel
A sessão vem do login e vale 30 dias:
curl -X POST "https://api.bridgesagents.com/api/v1/auth/login" -H "Content-Type: application/json" \
-d '{"email": "voce@sualoja.com.br", "password": "…"}'
# → { "token": "abs_…", "expiresAt": "…", "user": { … } }O cadastro de lojista (POST /api/v1/auth/signup) cria a empresa, a primeira loja e o usuário de uma vez; o de desenvolvedor (POST /api/v1/auth/signup/developer) pede só nome da empresa ou projeto, seu nome, e-mail e senha. Os dois já devolvem a sessão. POST /api/v1/auth/logout encerra a sessão.
A chave de agente continua valendo para agentes que não usam OAuth.