Pulse API
Crea leads, sube inventario, lee tu workspace desde cualquier sistema. Authentication via Bearer API key generada en Configuración → API keys.
Autenticación
Todas las peticiones requieren el header Authorization: Bearer pk_….
curl -H "Authorization: Bearer pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ https://pulse-one-beta.vercel.app/api/v1/me
Las keys son por workspace. Cada request escribe en el workspace al que pertenece la key. La key se muestra solo una vez al crearla; guárdala en un password manager o secret store.
GET /api/v1/me
Verifica la key y devuelve info del workspace.
curl -H "Authorization: Bearer pk_..." \
https://pulse-one-beta.vercel.app/api/v1/me
# Response 200
{
"workspace": {
"id": "uuid",
"name": "GPA",
"slug": "gpa-...",
"industry": "auto_dealer",
"enabled_modules": { "lead_scorer": true, ... }
},
"api_version": "v1"
}POST /api/v1/leads
Crea un lead nuevo. Dispara scoring async, auto-asignación, smart-match y webhooks salientes.
Requiere al menos uno de: full_name, email, phone.
curl -X POST -H "Authorization: Bearer pk_..." \
-H "Content-Type: application/json" \
https://pulse-one-beta.vercel.app/api/v1/leads \
-d '{
"full_name": "Juan Pérez",
"email": "juan@example.com",
"phone": "+52 55 1234 5678",
"source": "website_form",
"inventory_external_id": "GPA-001",
"source_details": { "campaign": "facebook_q2" }
}'
# Response 201
{
"id": "uuid",
"full_name": "Juan Pérez",
"email": "juan@example.com",
"phone": "+52 55 1234 5678",
"source": "website_form",
"status": "new",
"created_at": "2026-05-05T..."
}El campo source debe ser uno de: website_form, meta_lead_ads, mercadolibre_message, whatsapp_inbound, intercom_conversation, phone_call, walk_in, referral, other.
GET /api/v1/leads
Lista leads del workspace. Paginado por ?limit=N (max 200, default 50).
curl -H "Authorization: Bearer pk_..." \
"https://pulse-one-beta.vercel.app/api/v1/leads?limit=20&temperature=hot&status=new"
# Response 200
{
"data": [
{ "id": "...", "full_name": "...", "score": 85, ... }
],
"count": 20
}Filtros opcionales: ?status=new|contacted|..., ?temperature=hot|burning|...
POST /api/v1/inventory
Crea o upsertea unidades. Acepta un solo item o { items: [...] } hasta 200 a la vez. Upsert por (workspace_id, external_id).
curl -X POST -H "Authorization: Bearer pk_..." \
-H "Content-Type: application/json" \
https://pulse-one-beta.vercel.app/api/v1/inventory \
-d '{
"items": [
{
"external_id": "GPA-100",
"title": "Honda CR-V EX 2022",
"price_amount": 459000,
"data": { "make": "Honda", "model": "CR-V", "year": 2022, "km": 45000 },
"status": "available",
"images": ["https://..."]
}
]
}'
# Response 201
{ "upserted": 1, "inserted": 0, "total": 1 }GET /api/v1/inventory
Lista inventario del workspace. Mismas convenciones que /leads.
curl -H "Authorization: Bearer pk_..." \ "https://pulse-one-beta.vercel.app/api/v1/inventory?limit=50&status=available"
GET /api/v1/rastro
El rastro digital de una unidad: los clics al botón de WhatsApp sobre su ficha, las conversaciones que salieron de ellos, los leads interesados y el anuncio por el que entró cada conversación. Pensado para el momento de cerrar una venta en un CRM externo, para poder decir por dónde llegó el comprador.
Hace falta stock_id o external_id (los dos, si los tienes: las etiquetas de los clics llevan el stock y los leads apuntan al item). phone es opcional y es lo que convierte un clic anónimo en el clic de alguien. name es el sustituto cuando no hay teléfono, y es mucho más flojo: mira name_match en la respuesta antes de creértelo.
curl -H "Authorization: Bearer pk_..." \
"https://pulse-one-beta.vercel.app/api/v1/rastro?stock_id=GPA-5325511616&external_id=AT-recEsD…\
&phone=5512345678&name=Fernando&sale_date=2026-09-08&days=90"
# Response 200
{
"window": { "sale_date": "2026-09-08", "days": 90, "days_after": 2, "from": "...", "to": "..." },
"item": { "id": "...", "external_id": "AT-recEsD…", "title": "Mitsubishi Lancer GTS 2010" },
"clicks_item": [ { "id": "...", "item_label": "auto #GPA-5325511616",
"matched_conversation_id": "...", "matched_phone": "5212461376027",
"matched_phone_matches": true, "created_at": "...", "utm_source": null } ],
"clicks_person": [ ... ], // clics de ese teléfono, por cualquier unidad
"leads_item": [ ... ],
"leads_person": [ ... ],
"contacts_phone":[ ... ],
"contacts_name": [ ... ], // TODOS los que responden a ese nombre, nunca uno
"leads_name": [ ... ],
"name_match": { "asked": "fernando", "tokens": ["fernando"], "weak": true,
"ambiguous": true, "people": 2, "any_full": false,
"truncated": false },
"conversations": [ { "id": "...", "channel": "whatsapp", "last_message_at": "...",
"contact_id": "..." } ],
"contacts": [ { "id": "...", "name": "Fernando", "phone": "5212461376027",
"phone_matches": true, "has_phone": true,
"name_matches": false, "name_match_full": false } ],
"ads": [ { "conversation_id": "...", "ad_id": "...", "ad_title": "..." } ],
"history_items": [ ... ],
"partial": false
}Parámetros: days (default 90, max 365) y days_after (default 2) mueven la ventana alrededor de sale_date (default hoy). Devuelve filas crudas y no propone nada: ordenar y puntuar es del consumidor.
Los teléfonos salen enteros. De cada fila va el número completo y un booleano que dice si coincide con el phone preguntado — la comparación la hace Pulse por los diez dígitos nacionales, que es lo único que aguanta las formas en que el mismo número vive en su base. El nombre es otra cosa. Empareja exacto si le mandas una sola palabra y por nombre+apellido si le mandas dos, devuelve a TODOS los que responden y te dice en name_match cuántos son y si el nombre es flojo o ambiguo. Nunca elige. Un 502 significa que no se pudo leer, que no es lo mismo que un rastro vacío.
Webhooks salientes
Para recibir notificaciones cuando algo importante pasa (lead nuevo, hot lead, smart match, etc.), configura webhooks en Configuración → Webhooks salientes. Pulse hace POST a tu URL con el evento.
Errores
Códigos HTTP estándar:
200/201— éxito400— payload inválido (miradetailsen el body)401— API key faltante o revocada500— error de servidor (raro)
Rate limits
Sin límites duros por ahora. Recomendamos no superar ~20 req/s por workspace. Si necesitas batch grandes, usa el endpoint POST /api/v1/inventory con arrayitems en lugar de N peticiones individuales.
¿Falta un endpoint que necesitas? Avísanos en hello@pulse.app.