Resumen
BridgesAgents reúne productos, precios e inventario de tiendas de cualquier segmento del comercio minorista (supermercado, electrónica, farmacia, moda...) en un formato listo para agentes de IA de compra.
Hay tres formas de consultar el catálogo, todas con la misma clave de agente:
- MCP, para agentes de IA (Claude, ChatGPT, agentes propios): el agente descubre y llama las tools por sí solo.
- API REST, para sistemas e integraciones tradicionales.
- UCP (Universal Commerce Protocol), para agentes que ya hablan ese estándar.
Empieza aquí: crea una cuenta de desarrollador, genera la clave de agente en Claves de agente en el panel y envíala en cada consulta en el header Authorization: Bearer abd_… (detalles en Autenticación).
| Recurso | URL |
|---|---|
| Servidor MCP (Streamable HTTP) | https://api.bridgesagents.com/mcp |
| API REST | https://api.bridgesagents.com/api/v1 |
| Referencia interactiva (Swagger) | https://api.bridgesagents.com/swagger-ui.html |
Conceptos
| Concepto | Qué es |
|---|---|
| Comercio | La empresa (identificada por su CNPJ, el registro fiscal de empresas de Brasil) que vende. |
| Tienda | Unidad física de un comercio, con dirección, coordenadas, cómo atiende (retiro en tienda, entrega por radio o por rangos de CEP, el código postal de Brasil) y horario. El precio y el inventario varían por tienda. El registro lo hace el comercio. |
| Producto | El artículo en sí, igual en cualquier tienda: nombre, marca, categoría, GTIN/EAN y unidad. No tiene precio. |
| Oferta | Producto × tienda: precio, precio promocional e inventario. Es lo que el agente compara para decidir dónde comprar. |
Detalles que el agente debe tener en cuenta:
effectivePricees el precio a pagar: el promocional cuando existe; si no, el normal.updatedAtindica cuándo se actualizaron el precio y el inventario.stale: truemarca una oferta sin actualizar hace más de 7 días (el precio puede haber cambiado); con más de 30 días ya no aparece para los agentes.soldByWeightindica venta por peso (p. ej., frutas y verduras): el precio es por kg y el valor final solo se conoce al preparar el pedido.- Unidades (
unit):UN(unidad),KG,G,L,ML. requiresPrescription: medicamento que exige receta. El agente no debe concluir la compra; indícale al consumidor que presente la receta en la farmacia.adult: true: producto para mayores de 18 (bebidas alcohólicas, tabaco). BridgesAgents solo lo marca; quien confirma la edad es el agente.inStoreOnly: true: solo se vende en el local (combustible). No entra en el carrito y no tiene retiro ni entrega: muestra el precio, la distancia ymapsUrl(ruta hasta la tienda). Para seguir el precio de la gasolina, busca conradiusKm.storeVerified: la empresa de la tienda tiene CNPJ activo en la Receita Federal (autoridad fiscal de Brasil).storeRatingystoreRatingCount: calificación media (1 a 5) y cuántas calificaciones de quienes compraron por BridgesAgents.kind:GOOD(producto físico),FUEL(combustible),SERVICE(servicio),BOOKABLE(viaje, reserva) oDIGITAL(curso, gift card). SoloGOODentra en el carrito; los demás se compran con elbuyUrlde la tienda.currencyes la moneda de los precios (ISO 4217, ej.:BRL).priceTypedice cómo leer el precio:FIXED(cerrado),FROM(desde),PER_NIGHT(por noche),PER_PERSON(por persona).fulfillmentdice cómo llega:DELIVERY,PICKUP,IN_STORE(en el local),AT_CUSTOMER(a domicilio),BOOKING(reserva) oDIGITAL. Servicios y reservas no tienen stock (stocknulo); lo digital puede ser ilimitado. Reservas y digitales valen desde cualquier lugar.- En el producto:
taxonomyId(categoría de la Google Product Taxonomy),mpn(código del fabricante) yattributes(datos del tipo:color,size,duration_minutes,max_guests...).
Ubicación del consumidor
La búsqueda y las ofertas aceptan la ubicación del consumidor. Con ella, solo aparecen tiendas que entregan allí o que están cerca para retirar (hasta 30 km), y cada oferta indica cómo atiende la tienda.
- Prefiere
latitudeylongitude: son precisas. Solo con elpostalCode(CEP), la coordenada viene de un servicio de CEP y muchas veces es apenas el centro de la ciudad; en ese caso la distancia viene condistanceApproximate: true. - La entrega aplica si el consumidor está dentro del radio de la tienda o en uno de los rangos de CEP que atiende. Los rangos de CEP funcionan incluso sin coordenadas, así que envía el CEP siempre que lo tengas.
Conectar vía MCP
El servidor usa el transporte Streamable HTTP en 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 solo aceptan servidores locales (stdio)
Usa mcp-remote como puente. Ejemplo de configuración (Claude Desktop, Cursor y similares):
{
"mcpServers": {
"bridgesagents": {
"command": "npx",
"args": ["mcp-remote", "https://api.bridgesagents.com/mcp", "--header", "Authorization:Bearer ${BRIDGESAGENTS_KEY}"],
"env": { "BRIDGESAGENTS_KEY": "abd_SUA_CHAVE" }
}
}
}Probar sin agente
MCP Inspector lista y ejecuta las tools desde el navegador. Elige Streamable HTTP, ingresa la URL de arriba y agrega el header Authorization con Bearer abd_….
Los clientes compatibles con OAuth (como Claude y MCP Inspector) no necesitan header: en el primer acceso reciben 401 con WWW-Authenticate, descubren el servidor de autorización, se registran solos y abren la página donde el consumidor inicia sesión (o crea una cuenta) y permite el acceso. Consulta Autenticación.
npx @modelcontextprotocol/inspectorTools MCP
search_products
Busca productos por nombre o marca, en cualquier segmento. Ignora acentos y mayúsculas, acepta comienzos de palabra (arro → arroz) y sinónimos, incluso regionales de Brasil (bateria → pilha, bolacha → biscoito, macaxeira → mandioca). Tolera errores de tipeo (arros → arroz) y entiende términos en inglés y español (rice → arroz, frijoles → feijão, haircut → corte).
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| query | string | sí | Texto de búsqueda, en portugués. Ej.: "fone bluetooth" (audífonos Bluetooth). |
| limit | número | no | Máximo de resultados, de 1 a 50. Predeterminado: 10. |
| postalCode | string | no | CEP (código postal de Brasil) del consumidor. Con ubicación, solo productos que alguna tienda atiende allí. |
| latitude, longitude | número | no | Coordenadas del consumidor (más precisas que el CEP). |
| radiusKm | número | no | Solo tiendas hasta esta distancia del consumidor, en km (hasta 100). Requiere ubicación. Ej.: gasolineras en un radio 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 las ofertas de un producto por tienda, de la más barata a la más cara (en empate, la más cercana).
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| productId | UUID | sí | id obtenido de search_products. |
| postalCode | string | no | Código postal del consumidor (en Brasil, el CEP; cep también se acepta). |
| country | string | no | País del consumidor, 2 letras (BR, US, PT). Por defecto: BR. Fuera de Brasil, el código postal se convierte en coordenada aproximada (OpenStreetMap). |
| latitude, longitude | número | no | Coordenadas del consumidor. |
| radiusKm | número | no | Solo tiendas hasta esta distancia del consumidor, en km (hasta 100). Requiere ubicación. Ej.: gasolineras en un radio 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 | Qué significa |
|---|---|
| distanceKm | Distancia en línea recta hasta la tienda. Nula si alguna de las partes no tiene coordenadas. |
| pickup | Se puede retirar en la tienda (retiro habilitado y tienda cerca del consumidor). |
| delivery | Condiciones de entrega (costo, plazo en minutos, pedido mínimo) si la tienda entrega allí; null si no entrega. coveredBy: cep_range (seguro), radius (coordenadas exactas) o radius_approximate (calculado con la coordenada del CEP: puede no aplicar, confírmalo con la tienda). Sin ubicación, muestra las condiciones con coveredBy null. |
| openNow | Si la tienda está abierta ahora, en su zona horaria. Nulo si la tienda no informó horario. |
| buyUrl | Enlace para que el consumidor compre directo en la tienda: lleva al WhatsApp de la tienda (con el mensaje listo, con producto y precio) o a su sitio web. Nulo si la tienda no informó un canal de compra. Muéstraselo al consumidor cuando elija la oferta. |
create_cart
Arma un carrito en una tienda y devuelve confirmUrl: el enlace que el consumidor abre para revisarlo, ingresar su nombre y WhatsApp (y la dirección, si es entrega) y confirmar. El agente no cierra la compra solo ni recibe datos personales. El pedido llega al panel y al correo de la tienda; el pago es con la tienda. Si la tienda registró una clave Pix, el enlace muestra un código QR y un copiar y pegar con el monto del pedido.
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| storeId | UUID | sí | Tienda (de get_offers). Un carrito es de una sola tienda. |
| items | lista | sí | De 1 a 50 artículos { productId, quantity }. Cantidad fraccionada solo en productos vendidos por peso. |
| fulfillment | string | sí | Productos: pickup (retiro) o delivery (entrega). Servicios: in_store o at_customer (a domicilio). Reservas: booking. Digital: digital. Usa lo que acepta la oferta (fulfillment en get_offers). |
| postalCode | string | en entrega | Código postal del consumidor (CEP en Brasil); la tienda debe entregar allí. |
| note | string | no | Nota para la tienda (aparece en el pedido). |
| scheduledFor | string | en servicios | Fecha y hora pedidas, con zona horaria (ej.: 2026-11-05T14:00-03:00). Usa un horario libre de check_availability; fuera del horario de atención o completo se rechaza. |
| checkIn / checkOut | string | en reservas | Fechas AAAA-MM-DD. checkOut es obligatorio con precio por noche (la línea multiplica por las noches). |
| guests | número | en reservas | Personas. Obligatorio con precio por persona (la línea multiplica por los huéspedes). |
| externalReference | string | no | Tu id para este carrito (conversación o usuario en tu sistema), hasta 100 caracteres. Vuelve en get_cart, en Pedidos de los agentes y en los webhooks del desarrollador. |
{
"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
}Los productos con receta no entran en el carrito. Si algún artículo tiene un problema (sin stock, cantidad, tienda que no lo vende), no se crea nada y la respuesta lista cada problema. Al confirmar, se vuelven a revisar precio y stock: si el precio cambió, el consumidor ve el nuevo valor antes de confirmar.
check_availability
Agenda en tiempo real, antes de create_cart. Servicio: slots con los horarios libres dentro del horario de la tienda (cada duration_minutes) y los cupos que quedan (free, cuando la tienda informa capacity); usa un start como scheduledFor. Reserva: nights con cada noche y las unidades libres (free, cuando la tienda informa units; 0 = completo). El carrito rechaza horarios fuera del horario de atención o completos y sugiere los próximos libres.
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| storeId | UUID | sí | Tienda (de get_offers). |
| productId | UUID | sí | Servicio o reserva (de search_products). |
| from | AAAA-MM-DD | no | Primer día; hoy si está vacío. |
| days | entero | no | Cuántos días mirar, de 1 a 31 (por defecto 7). |
get_cart
Estado de un carrito creado con tu clave: OPEN, CONFIRMED (con el número y el estado del pedido) o EXPIRED. El enlace dura 24 horas. Mientras el pedido está NEW, order.respondBy indica hasta cuándo la tienda puede aceptarlo (2 h; 24 h para reservas y digitales, contando desde que abre la tienda): sin respuesta, se cancela solo con el motivo A loja não respondeu a tempo.
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| cartId | UUID | sí | id devuelto por create_cart. |
Próximas tools: quote_delivery y pago por el agente.
UCP y ACP
El mismo catálogo también está disponible en los formatos de comercio para agentes de Google y de OpenAI. Cada producto (el mismo en cualquier tienda, por GTIN) trae las ofertas de todas las tiendas. La compra sigue siendo en la tienda: todavía no hay checkout a través del agente.
UCP (Universal Commerce Protocol)
El perfil en https://api.bridgesagents.com/.well-known/ucp anuncia las capacidades dev.ucp.shopping.catalog.search y dev.ucp.shopping.catalog.lookup (versión 2026-08-25). Cada oferta de tienda es una variante: la tienda viene en seller, el precio en centavos ({"amount": 2490, "currency": "BRL"}) y url es el enlace de compra. Distancia, retiro, entrega y horario están en metadata. Envía context.postal_code para ver solo las tiendas que atienden al consumidor.
POST/ucp/v1/catalog/search
Búsqueda por texto, con filtros categories y price (min/max en centavos) y paginación 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
Productos por ids; los que no existen vuelven en messages con not_found.
POST/ucp/v1/catalog/product
Un producto por id, con todas sus ofertas.
ACP (Agentic Commerce Protocol, OpenAI)
Feed de productos de ChatGPT: un JSON por línea, una línea por oferta de tienda, con price en el formato 19.90 BRL e is_eligible_checkout: false. Las ofertas sin marca, sin imagen o sin canal de compra quedan fuera (el formato exige esos campos), al igual que los productos con receta. El header X-BridgesAgents-Skipped indica cuántas quedaron fuera.
El feed es de uso interno: el propio BridgesAgents lo genera en /feeds/acp/products.jsonl.gz y lo envía a OpenAI. Los agentes no necesitan descargarlo; para consultar el catálogo, usa MCP, REST o UCP con la clave de agente.
Importar catálogo
El comercio envía la hoja de cálculo que ya usa, en Excel (.xlsx) o CSV, desde el panel o por la API. Importar de nuevo actualiza precio e inventario, sin duplicar productos.
- La primera fila es el encabezado. El orden de las columnas no importa, y las columnas desconocidas se ignoran.
- Los nombres se comparan sin acentos, mayúsculas ni puntuación:
Preço de Vendaypreco_vendason la misma columna. - Los números aceptan el formato brasileño (
1.234,56,R$ 27,90; R$ es el real brasileño) y también27.90. - El CSV puede usar punto y coma, coma o tabulación, en UTF-8 o en el formato predeterminado de Excel en portugués.
- Las filas con problemas no impiden las demás: el resultado lista cada una con el número de fila y el motivo.
- El combustible (gasolina, etanol, diésel, GNV) se marca solo como venta únicamente en el local: sin carrito, aparece por la distancia a la gasolinera. Armas, munición, explosivos, cigarrillos electrónicos y drogas se rechazan.
- Límites: 5 MB y 10.000 filas por archivo.
Los encabezados de columna se reconocen por sus nombres en portugués (los de la tabla y de la plantilla). Las columnas de sí/no también aceptan yes/no y true/false.
| Columna | Nombres aceptados | Obligatoria | Observación |
|---|---|---|---|
| Nombre | nome, produto, descrição, item | sí | Hasta 300 caracteres. |
| Precio | preço, valor, preço de venda, valor unitário | sí | Mayor que cero. |
| EAN | ean, gtin, código de barras | no | 8, 12, 13 o 14 dígitos. Es lo que vincula tu producto con el mismo producto de otras tiendas. |
| Marca | marca, fabricante | no | Sin EAN, nombre + marca identifican el producto. |
| Categoría | categoria, departamento, seção | no | |
| Unidad | unidade, un, und | no | UN (predeterminada), KG, G, L o ML. |
| Precio promocional | preço promocional, promoção, preço oferta | no | Menor que el precio. |
| Inventario | estoque, quantidade, qtd, saldo | no | Predeterminado 0. |
| Vendido por peso | vendido por peso, por peso, granel | no | sim/não (sí/no). Sin la columna, la unidad KG cuenta como vendido por peso. |
| Exige receta | exige receita, receita, tarja, venda sob prescrição | no | sim/não (sí/no), o "tarja vermelha"/"tarja preta" (medicamentos de franja roja/negra en Brasil). Los agentes no concluyen la compra de estos productos. |
| Mayor de 18 | maior de 18, maiores de 18, 18, adulto | no | sim/não (sí/no). Las bebidas alcohólicas y el tabaco se marcan solos; el agente controla la edad. |
| Imagen | imagem, foto, url da imagem, image_link | no | Dirección https:// pública de la foto del producto. |
| Tipo de ítem | tipo de item, kind | no | producto, combustible, servicio, reserva o digital. Por defecto: producto. |
| Moneda | moeda, currency | no | Código de 3 letras (BRL, USD, EUR). Por defecto: BRL. En el formato del feed de Google, el precio puede traer la moneda (27.90 BRL). |
| Tipo de precio | tipo de preço, price_type | no | fijo, desde, por noche o por persona. Por defecto: fijo. |
| Atención | atendimento, fulfillment | no | entrega, retiro, en el local, a domicilio, reserva o digital (varios separados por coma). Por defecto: el del tipo. |
| MPN y SKU | mpn / sku | no | Código del fabricante (identifica el ítem sin EAN, junto con la marca) y el código en tu sistema. |
| Categoría de Google | google_product_category | no | Id o ruta de la Google Product Taxonomy (ej.: 2271 o Apparel & Accessories > Clothing). |
| Atributos | atributo_<nombre> (ej.: atributo_duration_minutes), color, size | no | Datos del tipo: color y talla del producto, duración del servicio, huéspedes de la reserva. También se acepta la planilla del feed de Google Merchant Center (title, price, sale_price, image_link...). |
Registro de tiendas
El comercio es responsable del registro de cada tienda: dirección, ubicación, cómo atiende y horario. Con eso los agentes saben si la tienda entrega al consumidor, si se puede retirar cerca y si está abierta. El panel muestra lo que falta en cada tienda.
- Coordenadas: ingresa las exactas (en Google Maps, clic derecho sobre la tienda y clic en los números). Si las dejas en blanco, usamos unas aproximadas por el CEP, que pueden ser solo el centro de la ciudad.
- Entrega: por radio (km desde la tienda), por rangos de CEP o ambos. El costo, el plazo en minutos y el pedido mínimo son por tienda.
- Canal de compra: WhatsApp de pedidos y/o sitio web. Es adonde el enlace “comprar en esta tienda” (
buyUrl) lleva al cliente. En el sitio web,{produto}en la URL se reemplaza por el nombre del producto. - Horario: por día de la semana, en la zona horaria del estado (UF) de la tienda. Dos turnos separados por coma,
24hofechado(cerrado). Cerrar después de medianoche (22:00-02:00) también vale.
Hoja de cálculo de tiendas (cadenas)
En Tiendas → Importar hoja de cálculo, la cadena registra y actualiza todas sus tiendas de una vez. El código identifica cada tienda: si existe, se actualiza; si no, se crea.
Como en el catálogo, los encabezados de columna se reconocen por sus nombres en portugués. Los días son seg, ter, qua, qui, sex, sab, dom (lunes a domingo).
| Columna | Nombres aceptados | Obligatoria | Ejemplo |
|---|---|---|---|
| Código | código, código da loja, filial | sí | BH-SAVASSI |
| Nombre | nome, loja, unidade | sí | Farmácia Centro |
| CEP / código postal | cep, codigo postal, zip | sí | 30140-010 |
| Dirección | rua/logradouro, número, complemento, bairro, cidade, UF | no* | Rua Pernambuco, 1200 |
| Coordenadas | latitude, longitude | no | -19.937410 / -43.934170 |
| Atención | retirada, entrega | no | sim / não (sí / no) |
| Entrega | raio km, taxa de entrega, prazo (min), pedido mínimo | no | 4 · 6,90 · 45 · 30,00 |
| Rangos de CEP | faixas cep, ceps atendidos | no | 30100-000 a 30199-999; 30210-000 |
| Horario | seg, ter, qua, qui, sex, sab, dom | no | 08:00-12:00, 14:00-20:00 · 24h · fechado |
| Canal de compra | whatsapp, site | no | (31) 99999-0000 · https://minhaloja.com.br/busca?q={produto} |
| Clave Pix | chave_pix, pix | no | Solo en Brasil: CPF, CNPJ, correo, celular o clave aleatoria. El consumidor paga por el enlace del pedido. |
* La ciudad y la UF (estado) se completan con el CEP cuando quedan en blanco. Descargar la hoja de cálculo modelo de tiendas
Conectar Bling
Quien usa Bling (un ERP brasileño) no necesita hoja de cálculo ni programación: en Integraciones, en el panel, el administrador conecta la cuenta de Bling, autoriza a BridgesAgents (solo lectura de productos, inventario y depósitos) y elige qué depósito abastece a cada tienda.
- Precio, foto, código de barras, marca y categoría vienen del registro del producto en Bling.
- El inventario de cada tienda es la suma del saldo disponible de los depósitos vinculados a ella.
- Los cambios de precio e inventario llegan en segundos; una sincronización completa se ejecuta todos los días de madrugada y aparece en Importaciones con Bling como origen.
- Un producto desactivado o eliminado en Bling queda con inventario cero.
- Los productos con variaciones (color, talla) todavía no se incluyen: por ahora, envíalos por la hoja de cálculo.
Conectar Nuvemshop
Quien vende en una tienda online Nuvemshop (Tiendanube) tampoco necesita hoja de cálculo: en Integraciones, en el panel, el administrador conecta la tienda, autoriza a BridgesAgents (solo lectura de productos e inventario) y elige qué tienda de BridgesAgents recibe el inventario de cada ubicación de Nuvemshop (con una sola tienda, esto es automático).
- Cada variante se convierte en un ítem, con el nombre del producto y los valores de la variante (ej.: "Camiseta Básica – Azul / M").
- Precio, precio promocional, foto, código de barras (cuando es un GTIN válido), marca y categoría vienen de Nuvemshop.
- Una variante sin control de inventario en Nuvemshop aparece como disponible, con 999 unidades.
- Los cambios en los productos llegan en segundos; una sincronización completa se ejecuta todos los días de madrugada y aparece en Importaciones con Nuvemshop como origen.
- Un producto oculto, fuera de la vitrina o eliminado en Nuvemshop queda con inventario cero. Una variante sin precio ("consultar") no se incluye.
Webhooks de pedidos
Para que el pedido llegue directo al sistema de la tienda (ERP, punto de venta, agenda, n8n, Zapier): en Integraciones, la administración o el desarrollador de la empresa registra una dirección https y elige la tienda (o todas) y los eventos. Los administradores reciben un correo por cada webhook nuevo.
order.created: el consumidor confirmó el pedido (el mismo momento del correo a la tienda).order.status_changed: la tienda aceptó, dejó listo, completó o canceló (concancelReason).order.paid: la tienda marcó el pedido como pagado (o lo deshizo:paidAtvuelve vacío).- Cada envío es un
POSTcon el pedido completo endata.order: artículos con elgtiny elskude la tienda, cliente, dirección, agenda de la reserva o del servicio, totales y moneda. Pueden aparecer campos nuevos; ninguno se renombra. - Los datos del cliente van solo a la tienda del pedido. Para devolver el estado, usa
POST /api/v1/me/orders/{id}/statuscon la clave de la tienda. - Número del pedido: al registrar, elige lo que acepta tu sistema. Solo números:
"number": 1042. Letras y números:"number": "AB1042". El camporeference("AB1042", el mismo identificador del Pix y del enlace del consumidor) va siempre. - Encabezado de acceso (opcional): si tu sistema exige un token fijo (
Authorization: Bearer …,X-Api-Key...), registra el nombre y el valor: va en cada envío, junto con la firma. El valor queda cifrado y el panel solo muestra el final. - Cuenta de desarrollador: en Webhooks, el desarrollador del agente recibe los mismos eventos de los pedidos hechos con sus claves, con
data.cart(id,externalReference,agentKeyId) y el pedido sin datos personales del comprador (customerydeliveryAddressvacíos). Así el bot avisa al usuario sin consultarget_carttodo el tiempo.
Ejemplo
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" }
}
}
}Verificar la firma
Al registrar, el panel muestra una sola vez el secreto (whsec_…). Cada envío trae X-BridgesAgents-Signature: t=<segundos>,v1=<hex>, donde v1 es el HMAC-SHA256, con el secreto, de t + "." + cuerpo (el cuerpo tal como llegó). Recházalo si no coincide o si t tiene más 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 "", 200Respuestas, reintentos y reenvío
- Responde 2xx en hasta 10 segundos y procesa después si tarda. No se siguen redirecciones.
- Sin 2xx, reintentamos a 1 min, 5 min, 30 min, 2 h y 12 h. Agotados (unas 15 h), el webhook se pausa y los administradores reciben un correo; los pedidos siguen en el panel.
- El mismo evento puede llegar más de una vez (reintento o reenvío): usa
X-BridgesAgents-Event-Id(igual aliddel cuerpo) para ignorar repetidos. El orden no está garantizado después de una falla: comparadata.order.updatedAt. - En el panel quedan los últimos envíos (30 días), con el error de cada uno, y los botones Enviar prueba (pedido ficticio, evento
webhook.test), Reenviar, Pausar/Reactivar y Cambiar secreto.
Probar en el sandbox
En el sandbox pruebas todo el flujo de tu agente sin una tienda real: las tiendas, los productos y los pedidos son ficticios, y tú haces el papel de la tienda y del checkout de pago.
- En el panel: en Pedidos de los agentes, abre un pedido y usa los botones para aceptar, marcar listo, completar o cancelar, y para avisar el pago (pagado con Pix, tarjeta o boleto, rechazado, reembolsado, disputado).
- Por la API, con la clave de agente (para pruebas automatizadas):
POST /api/v1/carts/{id}/sandbox/statuscon{"status": "ACCEPTED"}(ACCEPTED, READY, COMPLETED, CANCELLED) yPOST /api/v1/carts/{id}/sandbox/paymentcon{"status": "paid", "method": "pix"}(paid, refused, refunded, chargeback, pending; pix, card, boleto). - Cada simulación cambia el pedido de verdad: el consumidor recibe el aviso, tus webhooks reciben
order.status_changedyorder.paid, yget_cartmuestraorder.status,order.paymentStatus,order.paymentMethodyorder.paidAt. - Solo pedidos armados por tus claves. En producción estas rutas no existen: responde la tienda.
# 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"}'Herramienta completa: riesgo y zonas
Las cuentas de desarrollador pueden ver el nivel de riesgo de los pedidos que generaron sus agentes (GET /api/v1/me/agent-orders/{cartId}/risk) y los números por zona de las tiendas de la red (GET /api/v1/me/insights/regions), y buscar pedidos por zona (GET /api/v1/me/insights/orders?q=04001, por el inicio del código postal o por el nombre de la ciudad o del barrio): productos y categoría, pago, rechazos y el motivo, y el contacto (nombre, correo, teléfono) solo de pedidos con consentimiento: el operador del bot recoge el consentimiento del comprador, según la cláusula de su contrato con BridgesAgents. Lo que aparece depende de lo que el contrato libera, campo por campo, y cada búsqueda queda registrada. En el sandbox ya está todo liberado; en producción, mediante contrato con BridgesAgents.
Enviar catálogo por API
Para que el sistema de la tienda (ERP, tienda en línea, script) envíe precios e inventario automáticamente, sin hoja de cálculo. Mismas reglas y mensajes que la importación por hoja de cálculo.
1. Genera la clave
Hay dos tipos:
- Clave de la empresa (
POST /api/v1/me/api-keys): vale para todas las tiendas. Cada artículo indicastoreCode, el código de la tienda en tu sistema. Ideal para cadenas. - Clave de una tienda (
POST /api/v1/stores/{storeId}/api-keys): todo va a esa tienda ystoreCodese ignora.
En el panel, en Claves de API, o por la API con la sesión del comercio (ve Autenticación). La clave completa solo aparece en esa respuesta: guárdala de forma segura.
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. Envía los artículos con la clave
La clave va en el header X-Api-Key. Con la clave de la empresa, la tienda de cada artículo viene de storeCode; con la clave de una tienda, siempre es esa tienda. Cada artículo crea o actualiza la oferta de la tienda; los artículos que no se envíen quedan como están (para retirarlo de la venta, envía inventario 0). Hasta 1.000 artículos por solicitud.
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 | Obligatorio | Observación |
|---|---|---|---|
| name | texto | sí | Hasta 300 caracteres. |
| price | número | sí | Mayor que cero, con punto decimal (17.50). |
| gtin | texto | no | EAN con 8, 12, 13 o 14 dígitos. Vincula el artículo con el mismo producto de otras tiendas. |
| brand | texto | no | Sin GTIN, nombre + marca identifican el producto. |
| category | texto | no | |
| unit | texto | no | UN (predeterminada), KG, G, L o ML. |
| promoPrice | número | no | Menor que price. |
| stock | número | no | Predeterminado 0. |
| soldByWeight | true/false | no | Sin el campo, la unidad KG cuenta como vendido por peso. |
| requiresPrescription | true/false | no | Medicamento con receta. Los agentes no concluyen la compra. |
| adult | true/false | no | Mayores de 18. Las bebidas alcohólicas y el tabaco se marcan solos por el nombre y la categoría. |
| storeCode | texto | con clave de la empresa | Código de la tienda en tu sistema (registrado en Tiendas). |
| kind | texto | no | GOOD, FUEL, SERVICE, BOOKABLE o DIGITAL. Por defecto: GOOD. |
| currency | texto | no | ISO 4217 (BRL, USD, EUR). Por defecto: BRL. |
| priceType | texto | no | FIXED, FROM, PER_NIGHT o PER_PERSON (cada tipo acepta algunos). |
| fulfillment | lista | no | DELIVERY, PICKUP, IN_STORE, AT_CUSTOMER, BOOKING, DIGITAL. Por defecto: el del tipo. |
| mpn / sku | texto | no | Código del fabricante y código en tu sistema. |
| googleCategory | texto | no | Id o ruta de la Google Product Taxonomy. |
| attributes | objeto | no | Datos del tipo, ej.: {"duration_minutes": 60, "capacity": 2} (servicio: duración y atenciones simultáneas) o {"max_guests": 2, "check_in": "14:00", "units": 3} (reserva: unidades iguales por noche). |
| imageUrl | texto | no | Dirección https:// pública de la foto del producto. Vale la primera que se informe para el producto. |
La respuesta indica lo que entró. Los artículos con problemas no impiden los demás y aparecen en errors con su posición en items (empezando en 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 reemplazar una clave filtrada, genera otra y revoca la anterior en el panel (o con DELETE /api/v1/stores/{storeId}/api-keys/{keyId}).
API REST
Respuestas en JSON. Los campos de producto y oferta son los mismos de las tools MCP.
GET/api/v1/products?q={busca}&limit={1-50}&postalCode=&lat=&lng=
Busca productos. limit es opcional (predeterminado 20); postalCode, lat y lng filtran por las tiendas que atienden al consumidor (ve Ubicación del consumidor).
curl -H "Authorization: Bearer abd_SUA_CHAVE" "https://api.bridgesagents.com/api/v1/products?q=pilha%20aa"GET/r/{offerId}
El buyUrl de las ofertas: cuenta el clic y redirige al WhatsApp o al sitio web de la tienda.
GET/api/v1/products/{id}/offers
Ofertas del producto por tienda, de la más barata a la más 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
Igual que la tool check_availability: ?storeId=...&from=AAAA-MM-DD&days=7.
POST/api/v1/carts
Igual que la tool create_cart. Responde 201 con el carrito y confirmUrl; los artículos con problemas vuelven en 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}
Igual que la tool get_cart.
Con sesión del comercio (header Authorization: Bearer abs_…)
GET/api/v1/me
Comercio con sesión iniciada.
GET/api/v1/me/stores
Tiendas del comercio con sesión iniciada, con el registro completo y lo que falta en cada una (pending).
POST/api/v1/me/stores
Registra una tienda. PUT /api/v1/me/stores/{id} la actualiza.
POST/api/v1/me/stores/import
Hoja de cálculo de tiendas (multipart/form-data, campo file). Ve Registro de tiendas.
GET/api/v1/me/offers?q=&storeId=&stale=&page=&size=
Ofertas de las tiendas que puedes ver (gerente de tienda: solo las suyas), por nombre del producto: precio, inventario, cuándo se actualizó, stale y hidden. q busca en nombre, marca y código de barras; stale=true trae solo las que llevan más de 7 días sin actualizar. Paginada (size hasta 100).
GET/api/v1/me/offers/freshness
Ofertas desactualizadas por tienda: total, sin actualizar hace más de 7 días (stale) y hace más de 30 (hidden, ya ocultas para los agentes).
GET/api/v1/me/performance?days={1-90}
Rendimiento de las tiendas que la persona puede ver: apariciones para agentes, veces con el menor precio y clics en el enlace de compra, por tienda y por producto.
GET/api/v1/me/price-insights?days={1-90}&storeId=&limit=
Inteligencia de precios: para cada producto tuyo, cómo se compara tu precio con el de otras tiendas de la misma ciudad (sin identificarlas) y cuántas veces dejaste de ser el precio más bajo en las consultas de los agentes. days de 1 a 90.
GET/api/v1/me/agent-orders?status=&keyId=
Cuenta de desarrollador: carritos y pedidos de tus claves de agente, sin datos del comprador (cartStatus OPEN, CONFIRMED o EXPIRED; orderStatus, respondBy, paidAt, externalReference). status: open, confirmed, expired o cancelled. GET .../summary?days=30 trae carritos, confirmados, conversión y pedidos que la tienda no respondió.
GET/api/v1/me/orders?status=&storeId=
Pedidos de las tiendas que ves. status: novos (nuevos), andamento (en curso), concluidos (completados) o cancelados; sin él, todos. GET .../summary trae cuántos hay nuevos y en curso; GET .../{id}, el pedido con los datos del cliente.
POST/api/v1/me/orders/{id}/status
Cambia el estado: ACCEPTED, READY, COMPLETED o CANCELLED (con reason, que el cliente ve). Solo avanza en orden; se avisa al cliente por correo si dejó uno.
POST/api/v1/me/api-keys
Genera la clave de la empresa (todas las tiendas). GET lista y DELETE .../{keyId} revoca.
POST/api/v1/stores/{storeId}/catalog/import
Importa la hoja de cálculo de una de tus tiendas. Envíala como multipart/form-data en el 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}
Historial de importaciones (hoja de cálculo y API) de tus tiendas, de la más reciente a la más antigua. problems=true trae solo las que tienen artículos rechazados o fueron rechazadas.
GET/api/v1/me/imports/{id}
Una importación, con los artículos rechazados (errors): fila de la hoja de cálculo o posición en items, y el motivo.
Con clave de API de la tienda (header X-Api-Key: abk_…)
POST/api/v1/catalog/items
Envía artículos en JSON. Ve Enviar catálogo por API.
POST/api/v1/stores/{storeId}/api-keys
Con sesión del comercio: genera una clave para una de tus tiendas. GET en la misma ruta lista las claves (solo el comienzo de cada una) y DELETE .../api-keys/{keyId} revoca.
{
"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 probar los endpoints directamente en el navegador, usa la referencia interactiva (Swagger).
Errores y límites
| Situación | Resultado |
|---|---|
| Búsqueda vacía | Lista vacía. |
| limit fuera de 1 a 50 | Se ajusta al límite más cercano. |
| Producto sin ofertas o id inexistente | Lista vacía. |
| id que no es un UUID (REST) | HTTP 400. |
| Parámetro q ausente (REST) | HTTP 400. |
| Importación: archivo vacío, formato no soportado, sin columnas de nombre y precio o más de 10.000 filas | HTTP 400. |
| Importación: archivo de más de 5 MB | HTTP 413. |
| Consulta al catálogo (REST, MCP o UCP) sin clave de agente, o con clave inválida o revocada | HTTP 401. |
| Más de 120 consultas por minuto con la misma clave | HTTP 429, con Retry-After. |
| Sin sesión o sesión expirada (rutas del panel) | HTTP 401. |
| Cuenta de comercio creando clave de agente, o cuenta de desarrollador creando tienda | HTTP 403. |
| Tienda o importación que no es tuya (o no existe) | HTTP 404. |
| Envío por API: sin X-Api-Key, clave inválida o revocada | HTTP 401. |
| Búsqueda: CEP inválido, solo latitud o solo longitud, o coordenadas fuera de Brasil | HTTP 400. |
| Registro de tienda con datos inválidos (CEP, UF, coordenadas, horario, rango de CEP) | HTTP 400, con el motivo. |
| Envío por API: JSON mal formado, sin artículos o más de 1.000 artículos | HTTP 400. |
Los errores vienen en el formato application/problem+json (RFC 9457). El campo detail trae un mensaje en portugués que se puede mostrar al comercio.
Los mensajes detail de la API siempre están en portugués; el panel de BridgesAgents los traduce. Si los muestras a usuarios en otro idioma, mapéalos por el status HTTP o tradúcelos de tu lado.
Autenticación
| Quién | Cómo | Para qué |
|---|---|---|
| Agente (cuenta de desarrollador) | Clave de agente: Authorization: Bearer abd_… | Buscar productos y ofertas: REST, MCP y UCP. Obligatoria. |
| Asistente de IA del consumidor | OAuth 2.1: Authorization: Bearer abo_… | Buscar productos y ofertas en nombre de un consumidor que conectó el asistente. Alcance catalog. |
| Comercio | Sesión: Authorization: Bearer abs_… | Panel, importar hoja de cálculo, generar claves, ver el historial. Solo ve sus propias tiendas. |
| Sistema del comercio | Clave de la tienda: X-Api-Key: abk_… | Enviar el catálogo en JSON a esa tienda. |
Clave de agente
Ninguna consulta al catálogo es anónima. Crea la cuenta de desarrollador (sin CNPJ) y genera las claves en Claves de agente, en el panel. La clave aparece una sola vez; la base de datos guarda solo el hash. Usa una clave por agente o entorno: si una se filtra, revoca solo esa. El panel muestra cuántas consultas hizo cada clave por día, y el límite es de 120 por minuto por clave.
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)Planes y franquicia
Cada solicitud autenticada con clave de agente cuenta una consulta (búsqueda, ofertas, carrito o llamada MCP). El plan Gratis incluye 10.000 consultas al mes; al llegar a ellas, la API responde 429 con la explicación en detail hasta el día 1 del mes siguiente. Los planes pagos (Pro y Escala) no bloquean: el excedente se cobra por bloque de 1.000 consultas en la factura de fin de mes. Te avisamos por correo al 80% y al 100% de la franquicia, y el uso del mes aparece en Plan y facturación, en el panel. El sandbox no tiene franquicia.
Sandbox
Para probar sin afectar tiendas reales, usa el sandbox: sitio en https://sandbox.bridgesagents.com y API en https://api.sandbox.bridgesagents.com (MCP en /mcp). Tiene la misma versión que producción (cada cambio se publica en los dos), pero con su propia base de datos de tiendas y productos de ejemplo. Crea allí una cuenta de desarrollador: las claves empiezan con abd_test_ y no funcionan en producción (ni las de producción funcionan allí). Carritos y pedidos funcionan de punta a punta, solo que en las tiendas de ejemplo; los correos llegan con [Sandbox] en el asunto.
OAuth 2.1 (servidor MCP)
Seguimos la autorización de la especificación MCP: metadatos en /.well-known/oauth-protected-resource y /.well-known/oauth-authorization-server, registro dinámico en POST /oauth/register (solo clientes públicos), código con PKCE S256 obligatorio en /oauth/authorize y POST /oauth/token. El token de acceso (abo_) dura 1 hora y el de renovación (abr_) 30 días, y se cambia en cada uso; reutilizar un token de renovación o un código corta la conexión. POST /oauth/revoke revoca. El consumidor ve y desconecta las apps en Mis compras › Apps conectadas.
Solo son públicos el descubrimiento (/.well-known/ucp), esta documentación y el enlace de compra /r/…, que abre el consumidor.
Sesión del panel
La sesión viene del inicio de sesión y dura 30 días:
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": { … } }El registro de comercio (POST /api/v1/auth/signup) crea la empresa, la primera tienda y el usuario de una vez; el de desarrollador (POST /api/v1/auth/signup/developer) pide solo el nombre de la empresa o proyecto, tu nombre, correo y contraseña. Ambos ya devuelven la sesión. POST /api/v1/auth/logout cierra la sesión.
La clave de agente sigue funcionando para agentes que no usan OAuth.