VitrinaAPI

Leads

Las oportunidades que el workspace está trabajando: abrirlas, moverlas por el tablero, cerrarlas ganadas, perdidas o no calificadas, y leer el embudo.

Beta
Puede cambiar en cualquier momento, con una entrada en el changelog y aviso a quienes la llamaron recientemente — ver versionado.

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étodoRutaQué hace
GET/lead-outreach/statusFirst-touch status for one lead source
GET/leadsList leads
POST/leadsCreate a lead
DELETE/leads/{id}Delete a lead
GET/leads/{id}Get a lead
PUT/leads/{id}Update a lead
GET/leads/{id}/activityList a lead's activity timeline
PUT/leads/{id}/assignAssign a lead to an owner or team
GET/leads/{id}/conversationsList the conversations this opportunity spans
POST/leads/{id}/conversationsLink a conversation to a lead
DELETE/leads/{id}/conversations/{conversationId}Unlink a conversation from a lead
PUT/leads/{id}/deal-termsSet 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-touchOne lead's first-touch outcome
POST/leads/{id}/first-touch/retrySend the first message again, after fixing the buyer phone
GET/leads/{id}/interestsList what a lead concretely wants
POST/leads/{id}/interestsAdd 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}/lineaSet a lead's Línea (a person's choice)
PUT/leads/{id}/lostMark a lead as lost
PUT/leads/{id}/pipelineMove a lead to another board
PUT/leads/{id}/reopenReopen a closed lead
POST/leads/{id}/reviewRun the lead reviewer on this lead now
PUT/leads/{id}/stageMove a lead to another stage
PUT/leads/{id}/unqualifyMark a lead as unqualified
PUT/leads/{id}/wonMark a lead as won
POST/leads/from-conversationConvert a conversation into a lead
GET/leads/funnelLead funnel by stage
POST/leads/importBulk-import leads
GET/leads/kanbanLeads grouped by stage (board view)
GET/leads/statsLead score bands
GET/leads/summaryLead 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ámetroEnTipoObligatorioRestricciones
sourcequerystringsí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ámetroEnTipoObligatorioRestricciones
pipeline_idquerystringnomín. 1
stage_idquerystringnomín. 1
statusqueryopen \won \lost \
sourcequeryconversation \marketplace \manual \
intentquerybuy \sell \financing \
acquisition_typequerycompra \consignacion \unknown
owner_user_idqueryuuidno
team_idqueryuuidno
contact_idquerystringnomín. 1
linea_idqueryuuidno
project_idqueryuuidno
min_valuequerynumber | nullno≥ 0
max_valuequerynumber | nullno≥ 0
min_scorequeryinteger | nullno≥ 0, ≤ 100
max_scorequeryinteger | nullno≥ 0, ≤ 100
temperaturequerycold \warm \hot \
last_activity_afterquerystringnodate-time
qquerystringnomín. 1, máx. 200
sortquerylast_activity_desc \last_activity_asc \created_desc \
resource_typequeryvehicleno
resource_idqueryuuidno
card_kindqueryall \leads \solicitudes
first_touchqueryfailedno
first_touch_fromquerystringnodate-time
first_touch_toquerystringnodate-time
pagequeryintegerno≥ 1, por defecto 1
page_sizequeryintegerno≥ 1, ≤ 200, por defecto 25
fieldsquerysummary \fullno
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

CampoTipoObligatorioRestricciones
contact_iduuidsí
pipeline_iduuid—
stage_iduuid—
conversation_iduuid—
titlestringsímín. 1, máx. 500
notesstring | null—máx. 20000
sourceconversation \marketplace \manual \
intentbuy \sell \financing \
acquisition_typecompra \consignacion \unknown
source_refstring | null—máx. 500
value_amountnumber | null—≥ 0
value_currencystring | null—mín. 1, máx. 8
expected_close_atstring | null—date-time
owner_user_idstring | null—
team_idstring | null—
scoreinteger | null—≥ 0, ≤ 100
project_idstring | 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ámetroEnTipoObligatorioRestricciones
idpathstringsí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ámetroEnTipoObligatorioRestricciones
idpathstringsí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ámetroEnTipoObligatorioRestricciones
idpathstringsí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

CampoTipoObligatorioRestricciones
titlestring—mín. 1, máx. 500
notesstring | null—máx. 20000
value_amountnumber | null—≥ 0
value_currencystring | null—mín. 1, máx. 8
expected_close_atstring | null—date-time
owner_user_idstring | null—
team_idstring | null—
scoreinteger | null—≥ 0, ≤ 100
project_idstring | null—
temperaturehot \warm \cold
temperature_reasonstring | null—máx. 500
lost_reasonbought_elsewhere \financing_rejected \unit_unavailable \
acquisition_typecompra \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ámetroEnTipoObligatorioRestricciones
idpathstringsí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ámetroEnTipoObligatorioRestricciones
idpathstringsí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

CampoTipoObligatorioRestricciones
owner_user_idstring | null—
team_idstring | 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ámetroEnTipoObligatorioRestricciones
idpathstringsí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ámetroEnTipoObligatorioRestricciones
idpathstringsí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

CampoTipoObligatorioRestricciones
conversation_iduuidsí
make_primaryboolean—
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ámetroEnTipoObligatorioRestricciones
idpathstringsípatrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$
conversationIdpathuuidsí
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ámetroEnTipoObligatorioRestricciones
idpathstringsí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

CampoTipoObligatorioRestricciones
payment_methodcash \financing \credit_card \
down_payment_amountnumber | null—≥ 0
budget_max_amountnumber | null—≥ 0
has_trade_inboolean | null—
trade_in_descriptionstring | null—mín. 1, máx. 300
offer_amountnumber | null—≥ 0
offer_notestring | null—mín. 1, máx. 300
financing_term_monthsarray | null—
installment_amountnumber | null—≥ 0
max_down_payment_amountnumber | null—≥ 0
net_income_amountnumber | null—≥ 0
employerstring | null—mín. 1, máx. 300
employment_tenurestring | null—mín. 1, máx. 300
budget_currencyUF \CLP—
down_payment_currencyUF \CLP—
mortgage_preapproval_statusnot_started \in_progress \pre_approved \
mortgage_bankstring | null—mín. 1, máx. 300
mortgage_preapproved_amountnumber | null—≥ 0
mortgage_preapproved_currencyUF \CLP—
meets_rent_income_requirementboolean | null—
has_guarantorboolean | null—
applicant_full_namestring | null—mín. 1, máx. 200
applicant_rutstring | 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ámetroEnTipoObligatorioRestricciones
idpathstringsípatrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$
fieldpathpayment_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ámetroEnTipoObligatorioRestricciones
idpathstringsí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ámetroEnTipoObligatorioRestricciones
idpathstringsí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

CampoTipoObligatorioRestricciones
phonestring—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ámetroEnTipoObligatorioRestricciones
idpathstringsí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ámetroEnTipoObligatorioRestricciones
idpathstringsí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

CampoTipoObligatorioRestricciones
resource_typevehicle \property \product \
resource_idstring | null—
titlestring | null—mín. 1, máx. 500
quantitynumber | null—≥ 0
prioritylow \medium \high
notesstring | null—máx. 20000
metadataobject—
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ámetroEnTipoObligatorioRestricciones
idpathstringsípatrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$
interestIdpathuuidsí
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ámetroEnTipoObligatorioRestricciones
idpathstringsípatrón ^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|L-\d+)$
interestIdpathuuidsí

Cuerpo

CampoTipoObligatorioRestricciones
resource_typevehicle \property \product \
resource_idstring | null—
titlestring | null—mín. 1, máx. 500
quantitynumber | null—≥ 0
prioritylow \medium \high
notesstring | null—máx. 20000
metadataobject—
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ámetroEnTipoObligatorioRestricciones
idpathstringsí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

CampoTipoObligatorioRestricciones
linea_iduuidsí
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ámetroEnTipoObligatorioRestricciones
idpathstringsí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

CampoTipoObligatorioRestricciones
statuswon \lost \unqualified \
reasonstring | null—máx. 500
value_amountnumber | null—≥ 0
value_currencystring | 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ámetroEnTipoObligatorioRestricciones
idpathstringsí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

CampoTipoObligatorioRestricciones
pipeline_iduuidsí
reasonstring | 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ámetroEnTipoObligatorioRestricciones
idpathstringsí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ámetroEnTipoObligatorioRestricciones
idpathstringsí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ámetroEnTipoObligatorioRestricciones
idpathstringsí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

CampoTipoObligatorioRestricciones
stage_iduuidsí
reasonstring | null—máx. 500
suggestion_iduuid—
value_amountnumber | null—≥ 0
value_currencystring | 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ámetroEnTipoObligatorioRestricciones
idpathstringsí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

CampoTipoObligatorioRestricciones
statuswon \lost \unqualified \
reasonstring | null—máx. 500
value_amountnumber | null—≥ 0
value_currencystring | 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ámetroEnTipoObligatorioRestricciones
idpathstringsí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

CampoTipoObligatorioRestricciones
statuswon \lost \unqualified \
reasonstring | null—máx. 500
value_amountnumber | null—≥ 0
value_currencystring | 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

CampoTipoObligatorioRestricciones
conversation_iduuidsí
titlestring—mín. 1, máx. 500
notesstring—máx. 20000
pipeline_iduuid—
stage_iduuid—
owner_user_idstring | null—
value_amountnumber | 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ámetroEnTipoObligatorioRestricciones
pipeline_idquerystringsímín. 1
linea_idqueryuuidno
card_kindqueryall \leads \solicitudes
first_touchqueryfailedno
first_touch_fromquerystringnodate-time
first_touch_toquerystringnodate-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

CampoTipoObligatorioRestricciones
rowsobject[]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ámetroEnTipoObligatorioRestricciones
pipeline_idquerystringsímín. 1
linea_idqueryuuidno
card_kindqueryall \leads \solicitudes
first_touchqueryfailedno
first_touch_fromquerystringnodate-time
first_touch_toquerystringnodate-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ámetroEnTipoObligatorioRestricciones
pipeline_idquerystringnomí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ámetroEnTipoObligatorioRestricciones
pipeline_idquerystringnomí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ámetroEnTipoObligatorioRestricciones
dimensionpathowner_user_id \team_id \source
pipeline_idquerystringnomí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

En esta página