Leads
Las oportunidades que el workspace está trabajando: abrirlas, moverlas por el tablero, cerrarlas ganadas, perdidas o no calificadas, y leer el embudo.
Descarga la proyección completa de la API pública: openapi.json.
Mover leads por el embudo explica este recurso en prosa, con ejemplos ejecutables.
| Método | Ruta | Qué hace |
|---|---|---|
GET | /lead-outreach/status | First-touch status for one lead source |
GET | /leads | List leads |
POST | /leads | Create a lead |
DELETE | /leads/{id} | Delete a lead |
GET | /leads/{id} | Get a lead |
PUT | /leads/{id} | Update a lead |
GET | /leads/{id}/activity | List a lead's activity timeline |
PUT | /leads/{id}/assign | Assign a lead to an owner or team |
GET | /leads/{id}/conversations | List the conversations this opportunity spans |
POST | /leads/{id}/conversations | Link a conversation to a lead |
DELETE | /leads/{id}/conversations/{conversationId} | Unlink a conversation from a lead |
PUT | /leads/{id}/deal-terms | Set a lead's deal terms (human) |
DELETE | /leads/{id}/deal-terms/suggestions/{field} | Dismiss an AI deal-term suggestion (keep the human value) |
GET | /leads/{id}/first-touch | One lead's first-touch outcome |
POST | /leads/{id}/first-touch/retry | Send the first message again, after fixing the buyer phone |
GET | /leads/{id}/interests | List what a lead concretely wants |
POST | /leads/{id}/interests | Add an interest to a lead |
DELETE | /leads/{id}/interests/{interestId} | Remove a lead interest |
PATCH | /leads/{id}/interests/{interestId} | Update a lead interest |
PUT | /leads/{id}/linea | Set a lead's Línea (a person's choice) |
PUT | /leads/{id}/lost | Mark a lead as lost |
PUT | /leads/{id}/pipeline | Move a lead to another board |
PUT | /leads/{id}/reopen | Reopen a closed lead |
POST | /leads/{id}/review | Run the lead reviewer on this lead now |
PUT | /leads/{id}/stage | Move a lead to another stage |
PUT | /leads/{id}/unqualify | Mark a lead as unqualified |
PUT | /leads/{id}/won | Mark a lead as won |
POST | /leads/from-conversation | Convert a conversation into a lead |
GET | /leads/funnel | Lead funnel by stage |
POST | /leads/import | Bulk-import leads |
GET | /leads/kanban | Leads grouped by stage (board view) |
GET | /leads/stats | Lead score bands |
GET | /leads/summary | Lead pipeline summary |
GET | /leads/win-rate/{dimension} | Win rate by owner, team or source |
GET /lead-outreach/status
First-touch status for one lead source
Health and recent outcomes of the proactive first message for one lead source (chileautos, yapo, mercadolibre, website, …): which rail it uses, whether its account is usable, sends today, and the latest outcomes with the reason a lead was skipped.
website is ON by default for every workspace, and a portal (chileautos, mercadolibre, yapo) is ON by default once the workspace has an enabled marketplace account for it. With no block of its own such a source borrows the account and template chain of the first enabled source (config_origin: inherited, named in inherited_from), or uses the partner WhatsApp account and Vitrina's own templates — for a portal, the workspace's own first-contact templates first, then Vitrina's fallback ones (platform_default). An explicit block, enabled: false included, always wins. templates lists the WhatsApp ladder in send order with each template's state on that account: only APPROVED templates are ever sent; a PENDING or REJECTED one is shown so it is not silently skipped, and status: null means it is not on that account. When no template can be sent the first message goes by email, from the workspace mailbox. Each recent row carries its lead’s contact_id (one row per person on screen) and, on an error row, the classified error_code (undeliverable is Meta 131026; provider_frequency_capped and recipient_experiment are Meta holding marketing back), never the provider’s message.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
source | query | string | sí | mín. 1, máx. 64 |
curl https://api.vitrinadev.com/api/v1/lead-outreach/status \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"source": "website",
"enabled": true,
"contact_method": "whatsapp",
"template_name": "contacto_sitio_web_nombre",
"account": {
"id": "c3c3c3c3-0000-4000-8000-000000000001",
"name": "WhatsApp",
"enabled": true
},
"account_ok": true,
"config_origin": "platform_default",
"inherited_from": null,
"templates": [
{
"name": "contacto_sitio_web_nombre",
"language": "es",
"status": "APPROVED",
"category": "MARKETING",
"rejection_reason": null,
"synced_at": "2026-09-25T13:00:00.000Z"
},
{
"name": "contacto_sitio_web",
"language": "es",
"status": "PENDING",
"category": "UTILITY",
"rejection_reason": null,
"synced_at": "2026-09-25T13:00:00.000Z"
},
{
"name": "contacto_sitio_web_generico",
"language": "es",
"status": null,
"category": null,
"rejection_reason": null,
"synced_at": null
}
],
"sent_today": 3,
"daily_cap": 100000,
"recent": [
{
"id": "d4d4d4d4-0000-4000-8000-000000000001",
"status": "skipped",
"channel": "whatsapp",
"skip_reason": "no_phone",
"error_class": null,
"created_at": "2026-09-25T12:41:00.000Z",
"conversation_id": "e5e5e5e5-0000-4000-8000-000000000001",
"lead": {
"id": "f6f6f6f6-0000-4000-8000-000000000001",
"display_id": "L-42",
"title": "Consulta desde el sitio web",
"conversation_id": "e5e5e5e5-0000-4000-8000-000000000001"
}
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /leads
List leads
The flat list, paged (page / page_size, max 200) and filterable by board, stage, status, source, intent, owner, team, contact, value band, score band and last activity; q matches the title and the contact. temperature is a SHORTCUT over score (cold 0–39 · warm 40–69 · hot 70–100 · unscored score IS NULL) and explicit min_score / max_score win over it — do not confuse it with the temperature FIELD on a lead, which is a judgement somebody recorded about momentum and is not derived from the score. resource_type and resource_id must be supplied together and narrow to the leads interested in one record. meta.pagination.total is the match count, not the page size. A member whose role restricts record visibility sees only the leads they own.
fields=summary answers the SAME page with only the identifying and funnel scalars per row — id, display_id, title, status, source, intent, pipeline_id, stage_id, contact_id, value_amount, value_currency, owner_user_id, score, temperature, created_at, last_activity_at, closed_at, origin_conversation_id — plus stage_name and contact_name when the caller holds the scope that embed rides (stages:read, contacts:read); a name the caller may not read is ABSENT, never null. meta is unchanged. A 200-row page is ~525k characters at full (the default, byte-identical to omitting the parameter) and a fraction of that at summary; page with summary to choose, then GET /leads/\{id\} for the ones you need whole.
On a clinic (healthcare) workspace, value_amount on a WON lead is cash the patient paid, credited to that lead; before won it is the open presupuesto (a quote), not a sale. For return, ROAS, paid per ad or which ad brought paying patients, call ads_attributed_sales_list; never sum lead values.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
pipeline_id | query | string | no | mín. 1 |
stage_id | query | string | no | mín. 1 |
status | query | open \ | won \ | lost \ |
source | query | conversation \ | marketplace \ | manual \ |
intent | query | buy \ | sell \ | financing \ |
acquisition_type | query | compra \ | consignacion \ | unknown |
owner_user_id | query | uuid | no | |
team_id | query | uuid | no | |
contact_id | query | string | no | mín. 1 |
linea_id | query | uuid | no | |
project_id | query | uuid | no | |
min_value | query | number | null | no | ≥ 0 |
max_value | query | number | null | no | ≥ 0 |
min_score | query | integer | null | no | ≥ 0, ≤ 100 |
max_score | query | integer | null | no | ≥ 0, ≤ 100 |
temperature | query | cold \ | warm \ | hot \ |
last_activity_after | query | string | no | date-time |
q | query | string | no | mín. 1, máx. 200 |
sort | query | last_activity_desc \ | last_activity_asc \ | created_desc \ |
resource_type | query | vehicle | no | |
resource_id | query | uuid | no | |
card_kind | query | all \ | leads \ | solicitudes |
first_touch | query | failed | no | |
first_touch_from | query | string | no | date-time |
first_touch_to | query | string | no | date-time |
page | query | integer | no | ≥ 1, por defecto 1 |
page_size | query | integer | no | ≥ 1, ≤ 200, por defecto 25 |
fields | query | summary \ | full | no |
curl https://api.vitrinadev.com/api/v1/leads \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "99999999-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"display_id": "L-89",
"display_seq": 89,
"title": "María — prueba de manejo Corolla 2022",
"notes": null,
"status": "open",
"source": "conversation",
"source_ref": null,
"intent": "buy",
"contact_id": "22222222-0000-4000-8000-000000000001",
"pipeline_id": "44444444-0000-4000-8000-000000000001",
"stage_id": "55555555-0000-4000-8000-000000000001",
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"origin_conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"owner_user_id": "11111111-0000-4000-8000-000000000001",
"team_id": null,
"value_amount": 8990000,
"value_currency": "CLP",
"value_amount_close_confirmed_at": null,
"expected_close_at": "2026-10-15T00:00:00.000Z",
"score": 72,
"score_reason": "pidió hora para probar el auto y confirmó día",
"scored_at": "2026-09-21T14:02:11.000Z",
"temperature": "warm",
"temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
"temperature_at": "2026-09-21T14:02:11.000Z",
"won_lost_reason": null,
"lost_reason": null,
"lost_reason_source": null,
"lost_reason_at": null,
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": false,
"trade_in_description": null,
"offer_amount": null,
"offer_note": null,
"financing_term_months": [
24,
36
],
"installment_amount": null,
"max_down_payment_amount": null,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null,
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"down_payment_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {},
"closed_at": null,
"created_by": "11111111-0000-4000-8000-000000000001",
"created_at": "2026-09-18T13:44:02.115Z",
"updated_at": "2026-09-21T14:02:11.000Z",
"last_activity_at": "2026-09-21T14:02:11.000Z",
"contact": {
"id": "22222222-0000-4000-8000-000000000001",
"name": "María González",
"email": "[email protected]",
"phone": "+56912345001"
},
"stage": {
"id": "55555555-0000-4000-8000-000000000001",
"name": "Nuevo",
"slug": "new",
"position": 0,
"won_state": null,
"pipeline_id": "44444444-0000-4000-8000-000000000001"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000001",
"kind": "sales",
"name": "Ventas"
}
},
{
"id": "99999999-0000-4000-8000-000000000002",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"display_id": "L-90",
"display_seq": 90,
"title": "Consulta por financiamiento — Ana Soto",
"notes": null,
"status": "open",
"source": "website",
"source_ref": null,
"intent": "financing",
"contact_id": "22222222-0000-4000-8000-000000000001",
"pipeline_id": "44444444-0000-4000-8000-000000000001",
"stage_id": "55555555-0000-4000-8000-000000000002",
"conversation_id": null,
"origin_conversation_id": null,
"owner_user_id": null,
"team_id": null,
"value_amount": null,
"value_currency": "CLP",
"value_amount_close_confirmed_at": null,
"expected_close_at": null,
"score": null,
"score_reason": null,
"scored_at": null,
"temperature": null,
"temperature_reason": null,
"temperature_at": null,
"won_lost_reason": null,
"lost_reason": null,
"lost_reason_source": null,
"lost_reason_at": null,
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": false,
"trade_in_description": null,
"offer_amount": null,
"offer_note": null,
"financing_term_months": [
24,
36
],
"installment_amount": null,
"max_down_payment_amount": null,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null,
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"down_payment_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {},
"closed_at": null,
"created_by": null,
"created_at": "2026-09-19T09:12:44.000Z",
"updated_at": "2026-09-19T09:12:44.000Z",
"last_activity_at": "2026-09-19T09:12:44.000Z",
"contact": {
"id": "22222222-0000-4000-8000-000000000001",
"name": "Ana Soto",
"email": null,
"phone": "+56912345001"
},
"stage": {
"id": "55555555-0000-4000-8000-000000000002",
"name": "Contactado",
"slug": "contacted",
"position": 1,
"won_state": null,
"pipeline_id": "44444444-0000-4000-8000-000000000001"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000001",
"kind": "sales",
"name": "Ventas"
}
}
],
"meta": {
"pagination": {
"total": 16,
"limit": 25
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /leads
Create a lead
Opens an opportunity for an existing contact. pipeline_id defaults to the workspace's fallback SALES board (a lead cannot live on a ticket or vehicle board — 400 if you name one) and stage_id to that board's first column. source says WHERE it came from, intent says WHY (buy · sell · financing · trade_in, default buy); both are set at creation and are not part of the update body. With no owner_user_id but a team_id, the team's rotation picks the owner. Emits lead.created. Money is value_amount + value_currency and the pair travels together: a workspace may work in more than one currency, so the analytics endpoints break their totals down by_currency and flag is_mixed_currency rather than summing across them.
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
contact_id | uuid | sí | |
pipeline_id | uuid | — | |
stage_id | uuid | — | |
conversation_id | uuid | — | |
title | string | sí | mín. 1, máx. 500 |
notes | string | null | — | máx. 20000 |
source | conversation \ | marketplace \ | manual \ |
intent | buy \ | sell \ | financing \ |
acquisition_type | compra \ | consignacion \ | unknown |
source_ref | string | null | — | máx. 500 |
value_amount | number | null | — | ≥ 0 |
value_currency | string | null | — | mín. 1, máx. 8 |
expected_close_at | string | null | — | date-time |
owner_user_id | string | null | — | |
team_id | string | null | — | |
score | integer | null | — | ≥ 0, ≤ 100 |
project_id | string | null | — |
curl -X POST https://api.vitrinadev.com/api/v1/leads \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"contact_id": "22222222-0000-4000-8000-000000000001",
"pipeline_id": "44444444-0000-4000-8000-000000000001",
"title": "María — prueba de manejo Corolla 2022",
"source": "manual",
"intent": "buy",
"value_amount": 8990000,
"value_currency": "CLP",
"expected_close_at": "2026-10-15T00:00:00.000Z",
"owner_user_id": "11111111-0000-4000-8000-000000000001"
}'Ejemplo de respuesta (201)
{
"data": {
"id": "99999999-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"display_id": "L-89",
"display_seq": 89,
"title": "María — prueba de manejo Corolla 2022",
"notes": null,
"status": "open",
"source": "conversation",
"source_ref": null,
"intent": "buy",
"contact_id": "22222222-0000-4000-8000-000000000001",
"pipeline_id": "44444444-0000-4000-8000-000000000001",
"stage_id": "55555555-0000-4000-8000-000000000001",
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"origin_conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"owner_user_id": "11111111-0000-4000-8000-000000000001",
"team_id": null,
"value_amount": 8990000,
"value_currency": "CLP",
"value_amount_close_confirmed_at": null,
"expected_close_at": "2026-10-15T00:00:00.000Z",
"score": 72,
"score_reason": "pidió hora para probar el auto y confirmó día",
"scored_at": "2026-09-21T14:02:11.000Z",
"temperature": "warm",
"temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
"temperature_at": "2026-09-21T14:02:11.000Z",
"won_lost_reason": null,
"lost_reason": null,
"lost_reason_source": null,
"lost_reason_at": null,
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": false,
"trade_in_description": null,
"offer_amount": null,
"offer_note": null,
"financing_term_months": [
24,
36
],
"installment_amount": null,
"max_down_payment_amount": null,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null,
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"down_payment_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {},
"closed_at": null,
"created_by": "11111111-0000-4000-8000-000000000001",
"created_at": "2026-09-18T13:44:02.115Z",
"updated_at": "2026-09-21T14:02:11.000Z",
"last_activity_at": "2026-09-21T14:02:11.000Z",
"contact": {
"id": "22222222-0000-4000-8000-000000000001",
"name": "María González",
"email": "[email protected]",
"phone": "+56912345001"
},
"stage": {
"id": "55555555-0000-4000-8000-000000000001",
"name": "Nuevo",
"slug": "new",
"position": 0,
"won_state": null,
"pipeline_id": "44444444-0000-4000-8000-000000000001"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000001",
"kind": "sales",
"name": "Ventas"
}
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /leads/{id}
Delete a lead
Removes the opportunity and its history. The CONTACT is untouched — a deleted lead is an opportunity that should never have been opened, not a person who should be forgotten. A lead that really ended belongs on /lost or /unqualify, which keep the record and the reason.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
curl -X DELETE https://api.vitrinadev.com/api/v1/leads/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Responde: 204 · 400 · 401 · 403 · 404 · 409 · 429
GET /leads/{id}
Get a lead
One opportunity, with its contact, stage and pipeline embedded. On a clinic workspace it also carries origin: the Origen of its contact, Meta (with the ad), Orgánico (a linked contact with no ad touch) or Sin dato (no contact) — the attribution Vitrina Ads reports. On a clinic (healthcare) workspace, value_amount on a WON lead is cash the patient paid, credited to that lead; before won it is the open presupuesto (a quote), not a sale. For return, ROAS, paid per ad or which ad brought paying patients, call ads_attributed_sales_list; never sum lead values. \{id\} accepts the lead uuid or its ID visible (L-89) — the label is a lookup shortcut on the path only, never a value to store.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
curl https://api.vitrinadev.com/api/v1/leads/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "99999999-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"display_id": "L-89",
"display_seq": 89,
"title": "María — prueba de manejo Corolla 2022",
"notes": null,
"status": "open",
"source": "conversation",
"source_ref": null,
"intent": "buy",
"contact_id": "22222222-0000-4000-8000-000000000001",
"pipeline_id": "44444444-0000-4000-8000-000000000001",
"stage_id": "55555555-0000-4000-8000-000000000001",
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"origin_conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"owner_user_id": "11111111-0000-4000-8000-000000000001",
"team_id": null,
"value_amount": 8990000,
"value_currency": "CLP",
"value_amount_close_confirmed_at": null,
"expected_close_at": "2026-10-15T00:00:00.000Z",
"score": 72,
"score_reason": "pidió hora para probar el auto y confirmó día",
"scored_at": "2026-09-21T14:02:11.000Z",
"temperature": "warm",
"temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
"temperature_at": "2026-09-21T14:02:11.000Z",
"won_lost_reason": null,
"lost_reason": null,
"lost_reason_source": null,
"lost_reason_at": null,
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": false,
"trade_in_description": null,
"offer_amount": null,
"offer_note": null,
"financing_term_months": [
24,
36
],
"installment_amount": null,
"max_down_payment_amount": null,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null,
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"down_payment_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {},
"closed_at": null,
"created_by": "11111111-0000-4000-8000-000000000001",
"created_at": "2026-09-18T13:44:02.115Z",
"updated_at": "2026-09-21T14:02:11.000Z",
"last_activity_at": "2026-09-21T14:02:11.000Z",
"contact": {
"id": "22222222-0000-4000-8000-000000000001",
"name": "María González",
"email": "[email protected]",
"phone": "+56912345001"
},
"stage": {
"id": "55555555-0000-4000-8000-000000000001",
"name": "Nuevo",
"slug": "new",
"position": 0,
"won_state": null,
"pipeline_id": "44444444-0000-4000-8000-000000000001"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000001",
"kind": "sales",
"name": "Ventas"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /leads/{id}
Update a lead
Only the fields present in the body are written; at least one is required. source and intent are set at creation and are not editable, and the stage is moved with PUT /leads/\{id\}/stage rather than here. temperature is the recorded JUDGEMENT about momentum (hot · warm · cold): omitting it leaves it alone, sending null RETRACTS it — which is how a person undoes a wrong verdict. Setting owner_user_id reassigns the lead's conversations with it. Money is value_amount + value_currency and the pair travels together: a workspace may work in more than one currency, so the analytics endpoints break their totals down by_currency and flag is_mixed_currency rather than summing across them.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
title | string | — | mín. 1, máx. 500 |
notes | string | null | — | máx. 20000 |
value_amount | number | null | — | ≥ 0 |
value_currency | string | null | — | mín. 1, máx. 8 |
expected_close_at | string | null | — | date-time |
owner_user_id | string | null | — | |
team_id | string | null | — | |
score | integer | null | — | ≥ 0, ≤ 100 |
project_id | string | null | — | |
temperature | hot \ | warm \ | cold |
temperature_reason | string | null | — | máx. 500 |
lost_reason | bought_elsewhere \ | financing_rejected \ | unit_unavailable \ |
acquisition_type | compra \ | consignacion \ | unknown |
curl -X PUT https://api.vitrinadev.com/api/v1/leads/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"value_amount": 8750000,
"expected_close_at": "2026-10-31T00:00:00.000Z",
"temperature": "hot",
"temperature_reason": "volvió a escribir pidiendo la reserva"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "99999999-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"display_id": "L-89",
"display_seq": 89,
"title": "María — prueba de manejo Corolla 2022",
"notes": null,
"status": "open",
"source": "conversation",
"source_ref": null,
"intent": "buy",
"contact_id": "22222222-0000-4000-8000-000000000001",
"pipeline_id": "44444444-0000-4000-8000-000000000001",
"stage_id": "55555555-0000-4000-8000-000000000001",
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"origin_conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"owner_user_id": "11111111-0000-4000-8000-000000000001",
"team_id": null,
"value_amount": 8750000,
"value_currency": "CLP",
"value_amount_close_confirmed_at": null,
"expected_close_at": "2026-10-31T00:00:00.000Z",
"score": 72,
"score_reason": "pidió hora para probar el auto y confirmó día",
"scored_at": "2026-09-21T14:02:11.000Z",
"temperature": "hot",
"temperature_reason": "volvió a escribir pidiendo la reserva",
"temperature_at": "2026-09-21T14:02:11.000Z",
"won_lost_reason": null,
"lost_reason": null,
"lost_reason_source": null,
"lost_reason_at": null,
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": false,
"trade_in_description": null,
"offer_amount": null,
"offer_note": null,
"financing_term_months": [
24,
36
],
"installment_amount": null,
"max_down_payment_amount": null,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null,
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"down_payment_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {},
"closed_at": null,
"created_by": "11111111-0000-4000-8000-000000000001",
"created_at": "2026-09-18T13:44:02.115Z",
"updated_at": "2026-09-22T08:39:20.206Z",
"last_activity_at": "2026-09-22T08:39:20.206Z",
"contact": {
"id": "22222222-0000-4000-8000-000000000001",
"name": "María González",
"email": "[email protected]",
"phone": "+56912345001"
},
"stage": {
"id": "55555555-0000-4000-8000-000000000001",
"name": "Nuevo",
"slug": "new",
"position": 0,
"won_state": null,
"pipeline_id": "44444444-0000-4000-8000-000000000001"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000001",
"kind": "sales",
"name": "Ventas"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /leads/{id}/activity
List a lead's activity timeline
Newest first. Every line carries its author (ADR 0106 §3.1): the member who acted (with via when they acted through a connected app or a personal token — «Camila vía Claude»), the API key that acted («CRM propio (API)», named as it was then), the AI agent, or the system. kind says what happened and data is kind-specific; id is the timeline row's own legacy sequence number, not a uuid — lead_id beside it is the reference.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
curl https://api.vitrinadev.com/api/v1/leads/<id>/activity \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": 474,
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"lead_id": "99999999-0000-4000-8000-000000000001",
"kind": "stage_changed",
"actor_user_id": "11111111-0000-4000-8000-000000000001",
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"data": {
"reason": "la llamamos y confirmó la hora",
"from_stage_id": "55555555-0000-4000-8000-000000000001",
"to_stage_id": "55555555-0000-4000-8000-000000000002",
"from_stage_slug": "new",
"to_stage_slug": "contacted",
"from_stage_name": "Nuevo",
"to_stage_name": "Contactado",
"to_stage_category": "open"
},
"author": {
"kind": "member",
"id": "11111111-0000-4000-8000-000000000001",
"name": "Camila Rojas",
"via": {
"kind": "connected_app",
"name": "Claude"
}
},
"created_at": "2026-09-22T08:39:25.338Z"
},
{
"id": 473,
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"lead_id": "99999999-0000-4000-8000-000000000001",
"kind": "assigned",
"actor_user_id": null,
"conversation_id": null,
"data": {
"from_owner_user_id": null,
"to_owner_user_id": "11111111-0000-4000-8000-000000000001"
},
"author": {
"kind": "api_key",
"id": "c1c1c1c1-0000-4000-8000-000000000001",
"name": "CRM propio"
},
"created_at": "2026-09-21T14:02:11.000Z"
},
{
"id": 470,
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"lead_id": "99999999-0000-4000-8000-000000000001",
"kind": "created",
"actor_user_id": null,
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"data": {
"source": "conversation",
"title": "María — prueba de manejo Corolla 2022"
},
"author": {
"kind": "system",
"id": null,
"name": null
},
"created_at": "2026-09-18T13:44:02.115Z"
}
]
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /leads/{id}/assign
Assign a lead to an owner or team
ONE ASSIGNEE OWNS THE WHOLE RELATIONSHIP: reassigning a lead moves every conversation linked to it, and their tickets, to the same person. Send owner_user_id, team_id or both; an omitted key leaves that side alone, and null clears it. A team with no owner draws from the team's rotation. Emits lead.assigned.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
owner_user_id | string | null | — | |
team_id | string | null | — |
curl -X PUT https://api.vitrinadev.com/api/v1/leads/<id>/assign \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"owner_user_id": "11111111-0000-4000-8000-000000000001",
"team_id": "cccccccc-0000-4000-8000-000000000001"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "99999999-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"display_id": "L-89",
"display_seq": 89,
"title": "María — prueba de manejo Corolla 2022",
"notes": null,
"status": "open",
"source": "conversation",
"source_ref": null,
"intent": "buy",
"contact_id": "22222222-0000-4000-8000-000000000001",
"pipeline_id": "44444444-0000-4000-8000-000000000001",
"stage_id": "55555555-0000-4000-8000-000000000001",
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"origin_conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"owner_user_id": "11111111-0000-4000-8000-000000000001",
"team_id": "cccccccc-0000-4000-8000-000000000001",
"value_amount": 8990000,
"value_currency": "CLP",
"value_amount_close_confirmed_at": null,
"expected_close_at": "2026-10-15T00:00:00.000Z",
"score": 72,
"score_reason": "pidió hora para probar el auto y confirmó día",
"scored_at": "2026-09-21T14:02:11.000Z",
"temperature": "warm",
"temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
"temperature_at": "2026-09-21T14:02:11.000Z",
"won_lost_reason": null,
"lost_reason": null,
"lost_reason_source": null,
"lost_reason_at": null,
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": false,
"trade_in_description": null,
"offer_amount": null,
"offer_note": null,
"financing_term_months": [
24,
36
],
"installment_amount": null,
"max_down_payment_amount": null,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null,
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"down_payment_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {},
"closed_at": null,
"created_by": "11111111-0000-4000-8000-000000000001",
"created_at": "2026-09-18T13:44:02.115Z",
"updated_at": "2026-09-21T14:02:11.000Z",
"last_activity_at": "2026-09-21T14:02:11.000Z",
"contact": {
"id": "22222222-0000-4000-8000-000000000001",
"name": "María González",
"email": "[email protected]",
"phone": "+56912345001"
},
"stage": {
"id": "55555555-0000-4000-8000-000000000001",
"name": "Nuevo",
"slug": "new",
"position": 0,
"won_state": null,
"pipeline_id": "44444444-0000-4000-8000-000000000001"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000001",
"kind": "sales",
"name": "Ventas"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /leads/{id}/conversations
List the conversations this opportunity spans
A lead is ONE closable opportunity; a conversation is a temporary session. The customer comes back next week on another channel and it is still the same opportunity, so this relation — not a single conversation_id — is the answer to "which conversations belong to this lead". is_origin marks where the opportunity STARTED (a historical fact) and is_primary the thread it is worked on now (editable).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
curl https://api.vitrinadev.com/api/v1/leads/<id>/conversations \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"display_id": "C-122",
"channel": "whatsapp",
"status": "open",
"is_primary": true,
"is_origin": true,
"linked_at": "2026-09-18T13:44:02.115Z",
"linked_by_type": "system",
"last_message_date": "2026-09-21T14:01:58.000Z"
}
],
"meta": {
"total": 1
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /leads/{id}/conversations
Link a conversation to a lead
IDEMPOTENT: re-linking an existing pair answers linked: false and writes no second timeline entry. make_primary moves the primary flag onto this thread, demoting whichever held it. 404 for a lead or a conversation this credential cannot see — BOTH sides are checked, so a member restricted to their own records cannot attach a colleague's thread to a lead they own.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
conversation_id | uuid | sí | |
make_primary | boolean | — |
curl -X POST https://api.vitrinadev.com/api/v1/leads/<id>/conversations \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"make_primary": true
}'Ejemplo de respuesta (200)
{
"data": {
"linked": true,
"is_primary": true
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /leads/{id}/conversations/{conversationId}
Unlink a conversation from a lead
Detaching the ORIGIN conversation is allowed: the association is editable, but origin_conversation_id is a historical fact ("where this opportunity started") and stays put, because attribution keeps reading it. Answers \{ unlinked \} — false when there was no link to remove.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
conversationId | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/leads/<id>/conversations/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"unlinked": true
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /leads/{id}/deal-terms
Set a lead's deal terms (human)
Deal terms are twenty-one nullable facts: payment_method (cash | financing | credit_card | debit_card | mixed), down_payment_amount, budget_max_amount, offer_amount (in the lead's value_currency), has_trade_in (null = unknown, false = none), trade_in_description, offer_note, and the financing ones: financing_term_months (plazo(s) = number of cuotas, e.g. [12, 18, 24]), installment_amount (valor cuota), max_down_payment_amount (pie máximo), net_income_amount (renta líquida), employer, employment_tenure, and the real-estate ones: budget_currency / down_payment_currency / mortgage_preapproved_currency (UF | CLP, the currency the amount was stated in; null = the lead's value_currency), mortgage_preapproval_status (not_started | in_progress | pre_approved | rejected), mortgage_bank, mortgage_preapproved_amount, meets_rent_income_requirement and has_guarantor (aval) for an arriendo. Each carries provenance in deal_terms_meta (ai | human); an AI writer never overwrites a human-owned field — a disagreeing AI reading is kept in deal_terms_suggestions instead. Every field in the body becomes human-owned (source: human, the caller as actor) and its pending suggestion is removed; null clears a value but keeps it human-owned, so the next AI read proposes instead of re-filling it. Accepting a suggestion is this call with the suggested value. applicant_full_name / applicant_rut are the applicant's identity and are written to the lead's PRIMARY contact (legal_name, tax_id kind rut) — no provenance; 400 when the lead has no contact or the RUT check digit is wrong, 409 when another contact already holds that RUT. Changes land on the lead's timeline as deal_terms_changed. Returns the Oportunidad lead object. \{id\} accepts the lead uuid or its ID visible (L-89) — the label is a lookup shortcut on the path only, never a value to store.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
payment_method | cash \ | financing \ | credit_card \ |
down_payment_amount | number | null | — | ≥ 0 |
budget_max_amount | number | null | — | ≥ 0 |
has_trade_in | boolean | null | — | |
trade_in_description | string | null | — | mín. 1, máx. 300 |
offer_amount | number | null | — | ≥ 0 |
offer_note | string | null | — | mín. 1, máx. 300 |
financing_term_months | array | null | — | |
installment_amount | number | null | — | ≥ 0 |
max_down_payment_amount | number | null | — | ≥ 0 |
net_income_amount | number | null | — | ≥ 0 |
employer | string | null | — | mín. 1, máx. 300 |
employment_tenure | string | null | — | mín. 1, máx. 300 |
budget_currency | UF \ | CLP | — |
down_payment_currency | UF \ | CLP | — |
mortgage_preapproval_status | not_started \ | in_progress \ | pre_approved \ |
mortgage_bank | string | null | — | mín. 1, máx. 300 |
mortgage_preapproved_amount | number | null | — | ≥ 0 |
mortgage_preapproved_currency | UF \ | CLP | — |
meets_rent_income_requirement | boolean | null | — | |
has_guarantor | boolean | null | — | |
applicant_full_name | string | null | — | mín. 1, máx. 200 |
applicant_rut | string | null | — | mín. 1, máx. 20 |
curl -X PUT https://api.vitrinadev.com/api/v1/leads/<id>/deal-terms \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"payment_method": "financing",
"financing_term_months": [
12,
18,
24
],
"net_income_amount": 1900000,
"applicant_rut": "12.345.678-5"
}'Ejemplo de respuesta (200)
{
"id": "99999999-0000-4000-8000-000000000001",
"display_id": "L-89",
"title": "María — prueba de manejo Corolla 2022",
"status": "open",
"source": "mercadolibre",
"stage": {
"id": "55555555-0000-4000-8000-000000000001",
"name": "Contactado"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000001",
"name": "Venta de vehículos"
},
"score": 72,
"score_reason": "pidió hora para probar el auto y confirmó día",
"scored_at": "2026-09-21T14:02:11.000Z",
"facts_changed_at": "2026-09-21T13:40:00.000Z",
"temperature": "warm",
"value_currency": "CLP",
"deal_terms": {
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": true,
"trade_in_description": "Chery Tiggo 2 Pro 2023, 32.000 km",
"offer_amount": 10500000,
"offer_note": "Financiado · pendiente de aprobación",
"financing_term_months": [
12,
18,
24
],
"installment_amount": null,
"max_down_payment_amount": 5000000,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null
},
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"offer_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {
"offer_amount": {
"value": 10800000,
"reason": "subió la oferta a 10,8 millones",
"at": "2026-09-22T10:00:00.000Z"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /leads/{id}/deal-terms/suggestions/{field}
Dismiss an AI deal-term suggestion (keep the human value)
«Mantener la mía»: removes the pending AI suggestion for one field and leaves the human value as it is. Idempotent — no suggestion is a no-op. Returns the Oportunidad lead object. \{id\} accepts the lead uuid or its ID visible (L-89) — the label is a lookup shortcut on the path only, never a value to store.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
field | path | payment_method \ | down_payment_amount \ | budget_max_amount \ |
curl -X DELETE https://api.vitrinadev.com/api/v1/leads/<id>/deal-terms/suggestions/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"id": "99999999-0000-4000-8000-000000000001",
"display_id": "L-89",
"title": "María — prueba de manejo Corolla 2022",
"status": "open",
"source": "mercadolibre",
"stage": {
"id": "55555555-0000-4000-8000-000000000001",
"name": "Contactado"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000001",
"name": "Venta de vehículos"
},
"score": 72,
"score_reason": "pidió hora para probar el auto y confirmó día",
"scored_at": "2026-09-21T14:02:11.000Z",
"facts_changed_at": "2026-09-21T13:40:00.000Z",
"temperature": "warm",
"value_currency": "CLP",
"deal_terms": {
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": true,
"trade_in_description": "Chery Tiggo 2 Pro 2023, 32.000 km",
"offer_amount": 10500000,
"offer_note": "Financiado · pendiente de aprobación",
"financing_term_months": [
12,
18,
24
],
"installment_amount": null,
"max_down_payment_amount": 5000000,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null
},
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"offer_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {
"offer_amount": {
"value": 10800000,
"reason": "subió la oferta a 10,8 millones",
"at": "2026-09-22T10:00:00.000Z"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /leads/{id}/first-touch
One lead's first-touch outcome
Whether the proactive first message for this lead went out, and if not, why: status (none = never attempted, pending, sent, skipped, error), the skip_reason (invalid_phone carries the number the portal delivered in skip_evidence.raw_phone), the classified error_class/error_code of a failed send (undeliverable = WhatsApp could not reach the number), the conversation it opened, and the contact's current phone with phone_dialable. retryable says whether POST /leads/\{id\}/first-touch/retry would be accepted; retry_blocked_reason names why not (already_sent, in_progress, do_not_contact, source_disabled, no_contact).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
curl https://api.vitrinadev.com/api/v1/leads/<id>/first-touch \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"status": "skipped",
"skip_reason": "invalid_phone",
"skip_evidence": {
"raw_phone": "+90773361"
},
"error_class": null,
"error_code": null,
"conversation_id": null,
"source": "chileautos",
"contact_id": "01a14658-50d7-764b-89dd-601c87c24fd7",
"phone": "+90773361",
"phone_dialable": false,
"retryable": true,
"retry_blocked_reason": null
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /leads/{id}/first-touch/retry
Send the first message again, after fixing the buyer phone
Re-runs the proactive first touch for a lead whose first attempt was skipped or failed — typically because the portal delivered a phone WhatsApp cannot reach. Pass phone to correct the contact first (it must pass the dial gate: E.164 or a 9-digit Chilean number, else 400 invalid_phone). Uses the configured template and account of the lead's source, reopens the buyer's original inquiry as the context card, and answers with the rail's outcome: sent with the new conversation_id, or sent: false with the reason (burst_skip, no_template, daily_cap, …). 409 with the blocking reason when the first touch already went out, is in flight, the person asked not to be contacted, or the source is off.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
phone | string | — | mín. 6, máx. 32 |
curl -X POST https://api.vitrinadev.com/api/v1/leads/<id>/first-touch/retry \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "+56990773361"
}'Ejemplo de respuesta (200)
{
"data": {
"sent": true,
"reason": null,
"conversation_id": "c0c0c0c0-0000-4000-8000-000000000459",
"phone": "+56990773361"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /leads/{id}/interests
List what a lead concretely wants
A lead is the opportunity; an INTEREST is the thing being asked for, and there can be several. resource_type is vehicle · property · product · service · repair_order · custom, with resource_id pointing at the record when it exists in Vitrina and title carrying it in words when it does not ("un SUV gris, 2020 o más nuevo").
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
curl https://api.vitrinadev.com/api/v1/leads/<id>/interests \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "aaaaaaaa-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"lead_id": "99999999-0000-4000-8000-000000000001",
"resource_type": "vehicle",
"resource_id": "e1e1e1e1-0000-4000-8000-000000000001",
"title": "Toyota Corolla 2022",
"quantity": 1,
"priority": "high",
"notes": "lo quiere gris, con mantenimiento al día",
"metadata": {},
"created_at": "2026-09-22T08:39:26.884Z",
"updated_at": "2026-09-22T08:39:26.884Z",
"superseded_at": null
}
],
"meta": {
"total": 1
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /leads/{id}/interests
Add an interest to a lead
Provide resource_id, title, or both — one of the two is required, because an interest that names neither a record nor a description says nothing. 400 otherwise.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
resource_type | vehicle \ | property \ | product \ |
resource_id | string | null | — | |
title | string | null | — | mín. 1, máx. 500 |
quantity | number | null | — | ≥ 0 |
priority | low \ | medium \ | high |
notes | string | null | — | máx. 20000 |
metadata | object | — |
curl -X POST https://api.vitrinadev.com/api/v1/leads/<id>/interests \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"resource_type": "vehicle",
"resource_id": "e1e1e1e1-0000-4000-8000-000000000001",
"quantity": 1,
"priority": "high",
"notes": "lo quiere gris, con mantenimiento al día"
}'Ejemplo de respuesta (201)
{
"data": {
"id": "aaaaaaaa-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"lead_id": "99999999-0000-4000-8000-000000000001",
"resource_type": "vehicle",
"resource_id": "e1e1e1e1-0000-4000-8000-000000000001",
"title": "Toyota Corolla 2022",
"quantity": 1,
"priority": "high",
"notes": "lo quiere gris, con mantenimiento al día",
"metadata": {},
"created_at": "2026-09-22T08:39:26.884Z",
"updated_at": "2026-09-22T08:39:26.884Z",
"superseded_at": null
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /leads/{id}/interests/{interestId}
Remove a lead interest
Deletes the row and answers \{ id, deleted: true \} (200, not 204). Removes it from the record entirely — an interest the customer moved ON from is history worth keeping, so prefer adding the new one.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
interestId | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/leads/<id>/interests/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "aaaaaaaa-0000-4000-8000-000000000001",
"deleted": true
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /leads/{id}/interests/{interestId}
Update a lead interest
Only the fields present in the body are written; at least one is required. Use this when the ask itself changed — a different unit, a different quantity, a different priority.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
interestId | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
resource_type | vehicle \ | property \ | product \ |
resource_id | string | null | — | |
title | string | null | — | mín. 1, máx. 500 |
quantity | number | null | — | ≥ 0 |
priority | low \ | medium \ | high |
notes | string | null | — | máx. 20000 |
metadata | object | — |
curl -X PATCH https://api.vitrinadev.com/api/v1/leads/<id>/interests/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"priority": "medium"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "aaaaaaaa-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"lead_id": "99999999-0000-4000-8000-000000000001",
"resource_type": "vehicle",
"resource_id": "e1e1e1e1-0000-4000-8000-000000000001",
"title": "Toyota Corolla 2022",
"quantity": 1,
"priority": "medium",
"notes": "lo quiere gris, con mantenimiento al día",
"metadata": {},
"created_at": "2026-09-22T08:39:26.884Z",
"updated_at": "2026-09-22T08:39:26.884Z",
"superseded_at": null
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /leads/{id}/linea
Set a lead's Línea (a person's choice)
Every lead of a clinic carries exactly one Línea (linea on the lead: id, nombre, source). It starts from the ad that opened the conversation (source: ad), else from the lead's own words matched against the keywords of each Línea (keyword), is refined by the booked primera visita's prestación (prestacion), is General otherwise (default), and staff can correct it here (staff). A person's choice is final: nothing automatic changes it afterwards. The Línea must be one of the clinic's live Líneas (GET /clinic/lineas). Requires leads:write.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
linea_id | uuid | sí |
curl -X PUT https://api.vitrinadev.com/api/v1/leads/<id>/linea \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"linea_id": "5b1f0c1e-0000-4000-8000-000000000001"
}'Ejemplo de respuesta (200)
{
"data": {
"lead_id": "7c2d9a10-0000-4000-8000-000000000011",
"linea": {
"id": "5b1f0c1e-0000-4000-8000-000000000001",
"nombre": "Implantes",
"source": "staff"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /leads/{id}/lost
Mark a lead as lost
The opportunity was real and did not close. The lead MOVES to the lowest-position stage of that category on its board, so the outcome and the column can never disagree — 400 when the board has no stage of that category, which is a board a person has to fix rather than a request to retry. status, closed_at and won_lost_reason are derived from the landing stage, and a lead.stage_changed Evento fires alongside the outcome one. reason is the one field worth filling: it is what the win-rate and funnel reads are read against. Emits lead.lost.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
status | won \ | lost \ | unqualified \ |
reason | string | null | — | máx. 500 |
value_amount | number | null | — | ≥ 0 |
value_currency | string | null | — | mín. 1, máx. 8 |
curl -X PUT https://api.vitrinadev.com/api/v1/leads/<id>/lost \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"reason": "compró en otra parte"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "99999999-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"display_id": "L-89",
"display_seq": 89,
"title": "María — prueba de manejo Corolla 2022",
"notes": null,
"status": "lost",
"source": "conversation",
"source_ref": null,
"intent": "buy",
"contact_id": "22222222-0000-4000-8000-000000000001",
"pipeline_id": "44444444-0000-4000-8000-000000000001",
"stage_id": "55555555-0000-4000-8000-000000000007",
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"origin_conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"owner_user_id": "11111111-0000-4000-8000-000000000001",
"team_id": null,
"value_amount": 8990000,
"value_currency": "CLP",
"value_amount_close_confirmed_at": null,
"expected_close_at": "2026-10-15T00:00:00.000Z",
"score": 72,
"score_reason": "pidió hora para probar el auto y confirmó día",
"scored_at": "2026-09-21T14:02:11.000Z",
"temperature": "warm",
"temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
"temperature_at": "2026-09-21T14:02:11.000Z",
"won_lost_reason": "compró en otra parte",
"lost_reason": "bought_elsewhere",
"lost_reason_source": "jev",
"lost_reason_at": "2026-09-22T08:44:12.501Z",
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": false,
"trade_in_description": null,
"offer_amount": null,
"offer_note": null,
"financing_term_months": [
24,
36
],
"installment_amount": null,
"max_down_payment_amount": null,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null,
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"down_payment_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {},
"closed_at": "2026-09-22T08:44:10.331Z",
"created_by": "11111111-0000-4000-8000-000000000001",
"created_at": "2026-09-18T13:44:02.115Z",
"updated_at": "2026-09-21T14:02:11.000Z",
"last_activity_at": "2026-09-21T14:02:11.000Z",
"contact": {
"id": "22222222-0000-4000-8000-000000000001",
"name": "María González",
"email": "[email protected]",
"phone": "+56912345001"
},
"stage": {
"id": "55555555-0000-4000-8000-000000000007",
"name": "Perdido",
"slug": "lost",
"position": 7,
"won_state": "lost",
"pipeline_id": "44444444-0000-4000-8000-000000000001"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000001",
"kind": "sales",
"name": "Ventas"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /leads/{id}/pipeline
Move a lead to another board
Reclassifies the opportunity onto a different SALES board (400 for a ticket or vehicle board) and lands it on that board's first stage, re-deriving the lifecycle from the landing stage rather than leaving a closed lead parked in an open column. Emits lead.pipeline_changed, whose changes carries BOTH the board and the stage that moved with it; no separate lead.stage_changed fires, so a receiver never sees one board change twice.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
pipeline_id | uuid | sí | |
reason | string | null | — | máx. 500 |
curl -X PUT https://api.vitrinadev.com/api/v1/leads/<id>/pipeline \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"pipeline_id": "44444444-0000-4000-8000-000000000002",
"reason": "es una venta mayorista"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "99999999-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"display_id": "L-89",
"display_seq": 89,
"title": "María — prueba de manejo Corolla 2022",
"notes": null,
"status": "open",
"source": "conversation",
"source_ref": null,
"intent": "buy",
"contact_id": "22222222-0000-4000-8000-000000000001",
"pipeline_id": "44444444-0000-4000-8000-000000000002",
"stage_id": "55555555-0000-4000-8000-000000000003",
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"origin_conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"owner_user_id": "11111111-0000-4000-8000-000000000001",
"team_id": null,
"value_amount": 8990000,
"value_currency": "CLP",
"value_amount_close_confirmed_at": null,
"expected_close_at": "2026-10-15T00:00:00.000Z",
"score": 72,
"score_reason": "pidió hora para probar el auto y confirmó día",
"scored_at": "2026-09-21T14:02:11.000Z",
"temperature": "warm",
"temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
"temperature_at": "2026-09-21T14:02:11.000Z",
"won_lost_reason": null,
"lost_reason": null,
"lost_reason_source": null,
"lost_reason_at": null,
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": false,
"trade_in_description": null,
"offer_amount": null,
"offer_note": null,
"financing_term_months": [
24,
36
],
"installment_amount": null,
"max_down_payment_amount": null,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null,
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"down_payment_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {},
"closed_at": null,
"created_by": "11111111-0000-4000-8000-000000000001",
"created_at": "2026-09-18T13:44:02.115Z",
"updated_at": "2026-09-21T14:02:11.000Z",
"last_activity_at": "2026-09-21T14:02:11.000Z",
"contact": {
"id": "22222222-0000-4000-8000-000000000001",
"name": "María González",
"email": "[email protected]",
"phone": "+56912345001"
},
"stage": {
"id": "55555555-0000-4000-8000-000000000003",
"name": "Nuevo",
"slug": "new",
"position": 0,
"won_state": null,
"pipeline_id": "44444444-0000-4000-8000-000000000002"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000002",
"kind": "sales",
"name": "Ventas mayoristas"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /leads/{id}/reopen
Reopen a closed lead
Puts a won, lost or unqualified lead back in play on the first OPEN stage of its board, clearing closed_at and won_lost_reason. No body. The close is not erased — the timeline and the transition log keep it — so a reopened-and-re-won lead reads as the two events it was.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
curl -X PUT https://api.vitrinadev.com/api/v1/leads/<id>/reopen \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "99999999-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"display_id": "L-89",
"display_seq": 89,
"title": "María — prueba de manejo Corolla 2022",
"notes": null,
"status": "open",
"source": "conversation",
"source_ref": null,
"intent": "buy",
"contact_id": "22222222-0000-4000-8000-000000000001",
"pipeline_id": "44444444-0000-4000-8000-000000000001",
"stage_id": "55555555-0000-4000-8000-000000000001",
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"origin_conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"owner_user_id": "11111111-0000-4000-8000-000000000001",
"team_id": null,
"value_amount": 8990000,
"value_currency": "CLP",
"value_amount_close_confirmed_at": null,
"expected_close_at": "2026-10-15T00:00:00.000Z",
"score": 72,
"score_reason": "pidió hora para probar el auto y confirmó día",
"scored_at": "2026-09-21T14:02:11.000Z",
"temperature": "warm",
"temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
"temperature_at": "2026-09-21T14:02:11.000Z",
"won_lost_reason": null,
"lost_reason": null,
"lost_reason_source": null,
"lost_reason_at": null,
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": false,
"trade_in_description": null,
"offer_amount": null,
"offer_note": null,
"financing_term_months": [
24,
36
],
"installment_amount": null,
"max_down_payment_amount": null,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null,
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"down_payment_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {},
"closed_at": null,
"created_by": "11111111-0000-4000-8000-000000000001",
"created_at": "2026-09-18T13:44:02.115Z",
"updated_at": "2026-09-21T14:02:11.000Z",
"last_activity_at": "2026-09-21T14:02:11.000Z",
"contact": {
"id": "22222222-0000-4000-8000-000000000001",
"name": "María González",
"email": "[email protected]",
"phone": "+56912345001"
},
"stage": {
"id": "55555555-0000-4000-8000-000000000001",
"name": "Nuevo",
"slug": "new",
"position": 0,
"won_state": null,
"pipeline_id": "44444444-0000-4000-8000-000000000001"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000001",
"kind": "sales",
"name": "Ventas"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /leads/{id}/review
Run the lead reviewer on this lead now
Synchronous (typically 5–20 s): the same lead-reviewer pass the background worker runs — score, temperature, the stage ladder (auto move or suggestion) and the deal terms the conversation states. Returns the Oportunidad lead object. At most once per lead per 60 s: a repeat answers 429 with error.retry_after_seconds (and a Retry-After header). 409 when lead review is off for the workspace or the lead is closed; 502 when the review could not complete. \{id\} accepts the lead uuid or its ID visible (L-89) — the label is a lookup shortcut on the path only, never a value to store.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
curl -X POST https://api.vitrinadev.com/api/v1/leads/<id>/review \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"id": "99999999-0000-4000-8000-000000000001",
"display_id": "L-89",
"title": "María — prueba de manejo Corolla 2022",
"status": "open",
"source": "mercadolibre",
"stage": {
"id": "55555555-0000-4000-8000-000000000001",
"name": "Contactado"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000001",
"name": "Venta de vehículos"
},
"score": 72,
"score_reason": "pidió hora para probar el auto y confirmó día",
"scored_at": "2026-09-21T14:02:11.000Z",
"facts_changed_at": "2026-09-21T13:40:00.000Z",
"temperature": "warm",
"value_currency": "CLP",
"deal_terms": {
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": true,
"trade_in_description": "Chery Tiggo 2 Pro 2023, 32.000 km",
"offer_amount": 10500000,
"offer_note": "Financiado · pendiente de aprobación",
"financing_term_months": [
12,
18,
24
],
"installment_amount": null,
"max_down_payment_amount": 5000000,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null
},
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"offer_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {
"offer_amount": {
"value": 10800000,
"reason": "subió la oferta a 10,8 millones",
"at": "2026-09-22T10:00:00.000Z"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /leads/{id}/stage
Move a lead to another stage
THE move. The target must be a stage of the lead's own board and must be reachable from the current one — a stage graph that forbids the hop is a 400. Landing on a terminal column re-derives the lifecycle from that stage's category, so dragging a card to «Ganado» closes the lead exactly as PUT /leads/\{id\}/won does. Emits lead.stage_changed with changes.stage = \{ from, to \} and the author, plus the outcome Evento when the status actually flipped. A no-op move (already on that stage) emits nothing. value_amount (+ value_currency) is the REAL closing price and is acted on only when the target is a won stage: it overwrites the value and stamps value_amount_close_confirmed_at before the move, as PUT /leads/\{id\}/won does; for any other target it is ignored.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
stage_id | uuid | sí | |
reason | string | null | — | máx. 500 |
suggestion_id | uuid | — | |
value_amount | number | null | — | ≥ 0 |
value_currency | string | null | — | mín. 1, máx. 8 |
curl -X PUT https://api.vitrinadev.com/api/v1/leads/<id>/stage \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"stage_id": "55555555-0000-4000-8000-000000000002",
"reason": "la llamamos y confirmó la hora"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "99999999-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"display_id": "L-89",
"display_seq": 89,
"title": "María — prueba de manejo Corolla 2022",
"notes": null,
"status": "open",
"source": "conversation",
"source_ref": null,
"intent": "buy",
"contact_id": "22222222-0000-4000-8000-000000000001",
"pipeline_id": "44444444-0000-4000-8000-000000000001",
"stage_id": "55555555-0000-4000-8000-000000000002",
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"origin_conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"owner_user_id": "11111111-0000-4000-8000-000000000001",
"team_id": null,
"value_amount": 8990000,
"value_currency": "CLP",
"value_amount_close_confirmed_at": null,
"expected_close_at": "2026-10-15T00:00:00.000Z",
"score": 72,
"score_reason": "pidió hora para probar el auto y confirmó día",
"scored_at": "2026-09-21T14:02:11.000Z",
"temperature": "warm",
"temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
"temperature_at": "2026-09-21T14:02:11.000Z",
"won_lost_reason": null,
"lost_reason": null,
"lost_reason_source": null,
"lost_reason_at": null,
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": false,
"trade_in_description": null,
"offer_amount": null,
"offer_note": null,
"financing_term_months": [
24,
36
],
"installment_amount": null,
"max_down_payment_amount": null,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null,
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"down_payment_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {},
"closed_at": null,
"created_by": "11111111-0000-4000-8000-000000000001",
"created_at": "2026-09-18T13:44:02.115Z",
"updated_at": "2026-09-22T08:39:25.338Z",
"last_activity_at": "2026-09-22T08:39:25.338Z",
"contact": {
"id": "22222222-0000-4000-8000-000000000001",
"name": "María González",
"email": "[email protected]",
"phone": "+56912345001"
},
"stage": {
"id": "55555555-0000-4000-8000-000000000002",
"name": "Contactado",
"slug": "contacted",
"position": 1,
"won_state": null,
"pipeline_id": "44444444-0000-4000-8000-000000000001"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000001",
"kind": "sales",
"name": "Ventas"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /leads/{id}/unqualify
Mark a lead as unqualified
There was never an opportunity here — the wrong product, the wrong workspace, a duplicate, a test. A DISTINCT outcome from lost, and the distinction is the point: unqualified leads are excluded from win rate on both sides, so qualifying early never looks like losing. The lead MOVES to the lowest-position stage of that category on its board, so the outcome and the column can never disagree — 400 when the board has no stage of that category, which is a board a person has to fix rather than a request to retry. status, closed_at and won_lost_reason are derived from the landing stage, and a lead.stage_changed Evento fires alongside the outcome one. Emits lead.unqualified.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
status | won \ | lost \ | unqualified \ |
reason | string | null | — | máx. 500 |
value_amount | number | null | — | ≥ 0 |
value_currency | string | null | — | mín. 1, máx. 8 |
curl -X PUT https://api.vitrinadev.com/api/v1/leads/<id>/unqualify \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"reason": "buscaba un servicio que no ofrecemos"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "99999999-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"display_id": "L-89",
"display_seq": 89,
"title": "María — prueba de manejo Corolla 2022",
"notes": null,
"status": "unqualified",
"source": "conversation",
"source_ref": null,
"intent": "buy",
"contact_id": "22222222-0000-4000-8000-000000000001",
"pipeline_id": "44444444-0000-4000-8000-000000000001",
"stage_id": "55555555-0000-4000-8000-000000000003",
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"origin_conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"owner_user_id": "11111111-0000-4000-8000-000000000001",
"team_id": null,
"value_amount": 8990000,
"value_currency": "CLP",
"value_amount_close_confirmed_at": null,
"expected_close_at": "2026-10-15T00:00:00.000Z",
"score": 72,
"score_reason": "pidió hora para probar el auto y confirmó día",
"scored_at": "2026-09-21T14:02:11.000Z",
"temperature": "warm",
"temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
"temperature_at": "2026-09-21T14:02:11.000Z",
"won_lost_reason": "buscaba un servicio que no ofrecemos",
"lost_reason": null,
"lost_reason_source": null,
"lost_reason_at": null,
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": false,
"trade_in_description": null,
"offer_amount": null,
"offer_note": null,
"financing_term_months": [
24,
36
],
"installment_amount": null,
"max_down_payment_amount": null,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null,
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"down_payment_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {},
"closed_at": "2026-09-22T08:44:10.331Z",
"created_by": "11111111-0000-4000-8000-000000000001",
"created_at": "2026-09-18T13:44:02.115Z",
"updated_at": "2026-09-21T14:02:11.000Z",
"last_activity_at": "2026-09-21T14:02:11.000Z",
"contact": {
"id": "22222222-0000-4000-8000-000000000001",
"name": "María González",
"email": "[email protected]",
"phone": "+56912345001"
},
"stage": {
"id": "55555555-0000-4000-8000-000000000003",
"name": "No calificado",
"slug": "unqualified",
"position": 8,
"won_state": null,
"pipeline_id": "44444444-0000-4000-8000-000000000001"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000001",
"kind": "sales",
"name": "Ventas"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /leads/{id}/won
Mark a lead as won
The opportunity closed in the workspace's favour. The lead MOVES to the lowest-position stage of that category on its board, so the outcome and the column can never disagree — 400 when the board has no stage of that category, which is a board a person has to fix rather than a request to retry. status, closed_at and won_lost_reason are derived from the landing stage, and a lead.stage_changed Evento fires alongside the outcome one. value_amount here is the REAL closing figure — distinct from any earlier estimate on the lead — and is the only status endpoint that acts on it: it overwrites the value and stamps value_amount_close_confirmed_at. Omit it to leave the estimate untouched. Emits lead.won.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | patrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$ |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
status | won \ | lost \ | unqualified \ |
reason | string | null | — | máx. 500 |
value_amount | number | null | — | ≥ 0 |
value_currency | string | null | — | mín. 1, máx. 8 |
curl -X PUT https://api.vitrinadev.com/api/v1/leads/<id>/won \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"reason": "cerró con financiamiento propio",
"value_amount": 8750000,
"value_currency": "CLP"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "99999999-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"display_id": "L-89",
"display_seq": 89,
"title": "María — prueba de manejo Corolla 2022",
"notes": null,
"status": "won",
"source": "conversation",
"source_ref": null,
"intent": "buy",
"contact_id": "22222222-0000-4000-8000-000000000001",
"pipeline_id": "44444444-0000-4000-8000-000000000001",
"stage_id": "55555555-0000-4000-8000-000000000006",
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"origin_conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"owner_user_id": "11111111-0000-4000-8000-000000000001",
"team_id": null,
"value_amount": 8750000,
"value_currency": "CLP",
"value_amount_close_confirmed_at": "2026-09-22T08:41:32.967Z",
"expected_close_at": "2026-10-15T00:00:00.000Z",
"score": 72,
"score_reason": "pidió hora para probar el auto y confirmó día",
"scored_at": "2026-09-21T14:02:11.000Z",
"temperature": "warm",
"temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
"temperature_at": "2026-09-21T14:02:11.000Z",
"won_lost_reason": "cerró con financiamiento propio",
"lost_reason": null,
"lost_reason_source": null,
"lost_reason_at": null,
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": false,
"trade_in_description": null,
"offer_amount": null,
"offer_note": null,
"financing_term_months": [
24,
36
],
"installment_amount": null,
"max_down_payment_amount": null,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null,
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"down_payment_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {},
"closed_at": "2026-09-22T08:41:32.977Z",
"created_by": "11111111-0000-4000-8000-000000000001",
"created_at": "2026-09-18T13:44:02.115Z",
"updated_at": "2026-09-21T14:02:11.000Z",
"last_activity_at": "2026-09-21T14:02:11.000Z",
"contact": {
"id": "22222222-0000-4000-8000-000000000001",
"name": "María González",
"email": "[email protected]",
"phone": "+56912345001"
},
"stage": {
"id": "55555555-0000-4000-8000-000000000006",
"name": "Ganado",
"slug": "won",
"position": 6,
"won_state": "won",
"pipeline_id": "44444444-0000-4000-8000-000000000001"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000001",
"kind": "sales",
"name": "Ventas"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /leads/from-conversation
Convert a conversation into a lead
Opens an opportunity out of a conversation that already has a contact: the contact is resolved from the thread (404 when it has none), the conversation becomes the lead's ORIGIN and its primary link, and a lead opened on a thread somebody already owns inherits that owner unless you name one. Emits lead.created with source: conversation.
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
conversation_id | uuid | sí | |
title | string | — | mín. 1, máx. 500 |
notes | string | — | máx. 20000 |
pipeline_id | uuid | — | |
stage_id | uuid | — | |
owner_user_id | string | null | — | |
value_amount | number | null | — | ≥ 0 |
curl -X POST https://api.vitrinadev.com/api/v1/leads/from-conversation \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"title": "María — prueba de manejo Corolla 2022",
"pipeline_id": "44444444-0000-4000-8000-000000000001",
"owner_user_id": "11111111-0000-4000-8000-000000000001"
}'Ejemplo de respuesta (201)
{
"data": {
"id": "99999999-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"display_id": "L-89",
"display_seq": 89,
"title": "María — prueba de manejo Corolla 2022",
"notes": null,
"status": "open",
"source": "conversation",
"source_ref": null,
"intent": "buy",
"contact_id": "22222222-0000-4000-8000-000000000001",
"pipeline_id": "44444444-0000-4000-8000-000000000001",
"stage_id": "55555555-0000-4000-8000-000000000001",
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"origin_conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"owner_user_id": "11111111-0000-4000-8000-000000000001",
"team_id": null,
"value_amount": 8990000,
"value_currency": "CLP",
"value_amount_close_confirmed_at": null,
"expected_close_at": "2026-10-15T00:00:00.000Z",
"score": 72,
"score_reason": "pidió hora para probar el auto y confirmó día",
"scored_at": "2026-09-21T14:02:11.000Z",
"temperature": "warm",
"temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
"temperature_at": "2026-09-21T14:02:11.000Z",
"won_lost_reason": null,
"lost_reason": null,
"lost_reason_source": null,
"lost_reason_at": null,
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": false,
"trade_in_description": null,
"offer_amount": null,
"offer_note": null,
"financing_term_months": [
24,
36
],
"installment_amount": null,
"max_down_payment_amount": null,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null,
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"down_payment_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {},
"closed_at": null,
"created_by": "11111111-0000-4000-8000-000000000001",
"created_at": "2026-09-18T13:44:02.115Z",
"updated_at": "2026-09-21T14:02:11.000Z",
"last_activity_at": "2026-09-21T14:02:11.000Z",
"contact": {
"id": "22222222-0000-4000-8000-000000000001",
"name": "María González",
"email": "[email protected]",
"phone": "+56912345001"
},
"stage": {
"id": "55555555-0000-4000-8000-000000000001",
"name": "Nuevo",
"slug": "new",
"position": 0,
"won_state": null,
"pipeline_id": "44444444-0000-4000-8000-000000000001"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000001",
"kind": "sales",
"name": "Ventas"
}
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
GET /leads/funnel
Lead funnel by stage
One row per stage of a board, in position order: how many OPEN leads sit there, what they are worth, and the MEDIAN hours a lead has been sitting on that stage — the number that says where the funnel is stuck. Money is value_amount + value_currency and the pair travels together: a workspace may work in more than one currency, so the analytics endpoints break their totals down by_currency and flag is_mixed_currency rather than summing across them.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
pipeline_id | query | string | sí | mín. 1 |
linea_id | query | uuid | no | |
card_kind | query | all \ | leads \ | solicitudes |
first_touch | query | failed | no | |
first_touch_from | query | string | no | date-time |
first_touch_to | query | string | no | date-time |
curl https://api.vitrinadev.com/api/v1/leads/funnel \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"stage_id": "55555555-0000-4000-8000-000000000001",
"stage_name": "Nuevo",
"stage_slug": "new",
"position": 0,
"open_count": 6,
"total_value": 193990000,
"total_value_by_currency": {
"CLP": 193990000
},
"is_mixed_currency": false,
"median_time_in_stage_hours": 350.91
},
{
"stage_id": "55555555-0000-4000-8000-000000000002",
"stage_name": "Contactado",
"stage_slug": "contacted",
"position": 1,
"open_count": 2,
"total_value": 15450000,
"total_value_by_currency": {
"CLP": 15450000
},
"is_mixed_currency": false,
"median_time_in_stage_hours": 427.53
}
]
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /leads/import
Bulk-import leads
Up to 2 000 rows in one call — a trade-show list, a spreadsheet, a migration from another system. Each row is matched to an existing contact by contact_email or contact_phone, and to a stage by stage_slug / an owner by owner_email. PARTIAL SUCCESS IS THE NORMAL OUTCOME and the status is 200 either way: the report says how many rows landed and gives a per-row ok with the lead_id or the reason it failed. Imported leads skip owner rotation — the file decides the owner.
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
rows | object[] | sí |
curl -X POST https://api.vitrinadev.com/api/v1/leads/import \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"rows": [
{
"title": "Consulta feria de autos — stand 12",
"contact_email": "[email protected]",
"value_amount": 7500000,
"currency": "CLP",
"stage_slug": "new",
"source": "import"
},
{
"title": "Consulta feria de autos — stand 14",
"contact_phone": "+56988887777",
"owner_email": "[email protected]"
}
]
}'Ejemplo de respuesta (200)
{
"data": {
"total": 2,
"inserted": 1,
"failed": 1,
"rows": [
{
"row": 1,
"ok": true,
"lead_id": "99999999-0000-4000-8000-000000000001"
},
{
"row": 2,
"ok": false,
"error": "No contact matched +56988887777"
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /leads/kanban
Leads grouped by stage (board view)
The board itself: every stage with its leads already nested, up to 200 per column — one request instead of one per column. The cards carry the same embeds and the same scope gating as GET /leads. On a clinic (healthcare) workspace, value_amount on a WON lead is cash the patient paid, credited to that lead; before won it is the open presupuesto (a quote), not a sale. For return, ROAS, paid per ad or which ad brought paying patients, call ads_attributed_sales_list; never sum lead values.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
pipeline_id | query | string | sí | mín. 1 |
linea_id | query | uuid | no | |
card_kind | query | all \ | leads \ | solicitudes |
first_touch | query | failed | no | |
first_touch_from | query | string | no | date-time |
first_touch_to | query | string | no | date-time |
curl https://api.vitrinadev.com/api/v1/leads/kanban \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"stages": [
{
"id": "55555555-0000-4000-8000-000000000001",
"name": "Nuevo",
"slug": "new",
"position": 0,
"won_state": null,
"is_terminal": false,
"leads": [
{
"id": "99999999-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"display_id": "L-89",
"display_seq": 89,
"title": "María — prueba de manejo Corolla 2022",
"notes": null,
"status": "open",
"source": "conversation",
"source_ref": null,
"intent": "buy",
"contact_id": "22222222-0000-4000-8000-000000000001",
"pipeline_id": "44444444-0000-4000-8000-000000000001",
"stage_id": "55555555-0000-4000-8000-000000000001",
"conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"origin_conversation_id": "bbbbbbbb-0000-4000-8000-000000000001",
"owner_user_id": "11111111-0000-4000-8000-000000000001",
"team_id": null,
"value_amount": 8990000,
"value_currency": "CLP",
"value_amount_close_confirmed_at": null,
"expected_close_at": "2026-10-15T00:00:00.000Z",
"score": 72,
"score_reason": "pidió hora para probar el auto y confirmó día",
"scored_at": "2026-09-21T14:02:11.000Z",
"temperature": "warm",
"temperature_reason": "respondió pidiendo confirmar la hora y no ha vuelto a escribir",
"temperature_at": "2026-09-21T14:02:11.000Z",
"won_lost_reason": null,
"lost_reason": null,
"lost_reason_source": null,
"lost_reason_at": null,
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": false,
"trade_in_description": null,
"offer_amount": null,
"offer_note": null,
"financing_term_months": [
24,
36
],
"installment_amount": null,
"max_down_payment_amount": null,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null,
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"down_payment_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {},
"closed_at": null,
"created_by": "11111111-0000-4000-8000-000000000001",
"created_at": "2026-09-18T13:44:02.115Z",
"updated_at": "2026-09-21T14:02:11.000Z",
"last_activity_at": "2026-09-21T14:02:11.000Z",
"contact": {
"id": "22222222-0000-4000-8000-000000000001",
"name": "María González",
"email": "[email protected]",
"phone": "+56912345001"
},
"stage": {
"id": "55555555-0000-4000-8000-000000000001",
"name": "Nuevo",
"slug": "new",
"position": 0,
"won_state": null,
"pipeline_id": "44444444-0000-4000-8000-000000000001"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000001",
"kind": "sales",
"name": "Ventas"
}
}
]
},
{
"id": "55555555-0000-4000-8000-000000000002",
"name": "Contactado",
"slug": "contacted",
"position": 1,
"won_state": null,
"is_terminal": false,
"leads": [
{
"id": "99999999-0000-4000-8000-000000000002",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"display_id": "L-90",
"display_seq": 90,
"title": "Consulta por financiamiento — Ana Soto",
"notes": null,
"status": "open",
"source": "website",
"source_ref": null,
"intent": "financing",
"contact_id": "22222222-0000-4000-8000-000000000001",
"pipeline_id": "44444444-0000-4000-8000-000000000001",
"stage_id": "55555555-0000-4000-8000-000000000002",
"conversation_id": null,
"origin_conversation_id": null,
"owner_user_id": null,
"team_id": null,
"value_amount": null,
"value_currency": "CLP",
"value_amount_close_confirmed_at": null,
"expected_close_at": null,
"score": null,
"score_reason": null,
"scored_at": null,
"temperature": null,
"temperature_reason": null,
"temperature_at": null,
"won_lost_reason": null,
"lost_reason": null,
"lost_reason_source": null,
"lost_reason_at": null,
"payment_method": "financing",
"down_payment_amount": 4000000,
"budget_max_amount": 11500000,
"has_trade_in": false,
"trade_in_description": null,
"offer_amount": null,
"offer_note": null,
"financing_term_months": [
24,
36
],
"installment_amount": null,
"max_down_payment_amount": null,
"net_income_amount": 1900000,
"employer": "CGE",
"employment_tenure": "15 años",
"budget_currency": null,
"down_payment_currency": null,
"mortgage_preapproval_status": null,
"mortgage_bank": null,
"mortgage_preapproved_amount": null,
"mortgage_preapproved_currency": null,
"meets_rent_income_requirement": null,
"has_guarantor": null,
"deal_terms_meta": {
"payment_method": {
"source": "ai",
"actor_id": null,
"actor_label": null,
"at": "2026-09-21T14:02:11.000Z"
},
"down_payment_amount": {
"source": "human",
"actor_id": "11111111-0000-4000-8000-000000000001",
"actor_label": "Camila Rojas",
"at": "2026-09-21T15:10:00.000Z"
}
},
"deal_terms_suggestions": {},
"closed_at": null,
"created_by": null,
"created_at": "2026-09-19T09:12:44.000Z",
"updated_at": "2026-09-19T09:12:44.000Z",
"last_activity_at": "2026-09-19T09:12:44.000Z",
"contact": {
"id": "22222222-0000-4000-8000-000000000001",
"name": "Ana Soto",
"email": null,
"phone": "+56912345001"
},
"stage": {
"id": "55555555-0000-4000-8000-000000000002",
"name": "Contactado",
"slug": "contacted",
"position": 1,
"won_state": null,
"pipeline_id": "44444444-0000-4000-8000-000000000001"
},
"pipeline": {
"id": "44444444-0000-4000-8000-000000000001",
"kind": "sales",
"name": "Ventas"
}
}
]
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /leads/stats
Lead score bands
The count in each SCORE band — cold 0–39, warm 40–69, hot 70–100, unscored — plus the average score. Bands over lead.score, not over the recorded temperature judgement; the two are different facts about a lead and neither is derived from the other.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
pipeline_id | query | string | no | mín. 1 |
curl https://api.vitrinadev.com/api/v1/leads/stats \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"total": 16,
"hot": 2,
"warm": 0,
"cold": 8,
"unscored": 6,
"avg_score": 28.5
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /leads/summary
Lead pipeline summary
How many leads are open, won, lost and unqualified, and what they are worth. Optionally narrowed to one board with pipeline_id. Money is value_amount + value_currency and the pair travels together: a workspace may work in more than one currency, so the analytics endpoints break their totals down by_currency and flag is_mixed_currency rather than summing across them. On a clinic (healthcare) workspace, value_amount on a WON lead is cash the patient paid, credited to that lead; before won it is the open presupuesto (a quote), not a sale. For return, ROAS, paid per ad or which ad brought paying patients, call ads_attributed_sales_list; never sum lead values.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
pipeline_id | query | string | no | mín. 1 |
curl https://api.vitrinadev.com/api/v1/leads/summary \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"open": 13,
"won": 2,
"lost": 1,
"unqualified": 0,
"total_value_open": 194077750,
"total_value_won": 2499000,
"total_value_open_by_currency": {
"CLP": 193990000,
"USD": 42750
},
"total_value_won_by_currency": {
"CLP": 2499000
},
"is_mixed_currency": true,
"is_mixed_currency_open": true
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /leads/win-rate/{dimension}
Win rate by owner, team or source
Won / (won + lost) grouped by owner_user_id, team_id or source. UNQUALIFIED leads are excluded from both sides on purpose: they were never a sale to win or lose, and counting them as losses would punish whoever is best at qualifying early. key is the owner or team uuid, or the source name — and the literal string unassigned for the bucket of closed leads that carried no owner or team at all.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
dimension | path | owner_user_id \ | team_id \ | source |
pipeline_id | query | string | no | mín. 1 |
curl https://api.vitrinadev.com/api/v1/leads/win-rate/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"dimension": "owner_user_id",
"key": "11111111-0000-4000-8000-000000000001",
"won": 2,
"lost": 1,
"win_rate": 0.6666666666666666
}
]
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429