Proyectos
Los proyectos de una inmobiliaria, sus tipologías, su stock de unidades (departamentos, casas, estacionamientos y bodegas) y su lista de precios en UF versionada y las cotizaciones en PDF con pie y dividendo, con importación desde Excel.
Descarga la proyección completa de la API pública: openapi.json.
| Método | Ruta | Qué hace |
|---|---|---|
DELETE | /case-assignments/{id} | Cancel an assignment |
POST | /case-assignments/{id}/link | A fresh link for an assignment, optionally re-sent |
GET | /channel-commissions | List channel commissions |
POST | /channel-commissions/{id}/cancel | Cancel a commission |
POST | /channel-commissions/{id}/pay | Mark a commission paid |
POST | /channel-commissions/milestones | Record that a lead’s negocio reached a milestone |
GET | /channel-partners | List corredores externos and referidores |
POST | /channel-partners | Add a corredor externo or referidor |
GET | /channel-partners/{id} | One corredor externo or referidor |
PATCH | /channel-partners/{id} | Edit a corredor externo or referidor |
GET | /channel-partners/{id}/claims | The buyers a partner brought |
POST | /channel-partners/{id}/claims | Credit a lead to a corredor or referidor |
GET | /cobranza | Overdue pie cuotas |
GET | /contratistas | List contratistas |
POST | /contratistas | Add a contratista |
DELETE | /contratistas/{id} | Remove a contratista |
GET | /contratistas/{id} | One contratista |
PATCH | /contratistas/{id} | Edit a contratista |
GET | /cotizacion-discount-approvals | The approver’s queue of discount requests |
POST | /cotizacion-discount-approvals/{id}/decision | Approve or refuse a discount request |
GET | /cotizaciones | List cotizaciones |
POST | /cotizaciones | Build a cotización draft |
DELETE | /cotizaciones/{id} | Discard a cotización draft |
GET | /cotizaciones/{id} | Get a cotización |
PATCH | /cotizaciones/{id} | Edit a cotización draft |
GET | /cotizaciones/{id}/discount-approval | Where a cotización’s discount stands against the caller’s limit |
POST | /cotizaciones/{id}/discount-approval | Ask a jefe de sala or gerente to allow the discount |
GET | /cotizaciones/{id}/pdf | The cotización as a PDF |
POST | /cotizaciones/{id}/reserva | Reserve a cotización’s unidades |
POST | /cotizaciones/{id}/send | Send the cotización PDF by WhatsApp or email |
GET | /cotizaciones/{id}/views | Who opened the cotización’s tracked link, and when |
POST | /cotizaciones/calculate | Calculate a cotización without saving it |
POST | /datahunter-import | Datahunter import steps 2–3: dry run, then load the history |
GET | /datahunter-import/batches | Datahunter import: past batches and what is staged |
POST | /datahunter-import/columns | Datahunter import step 1: read the files’ columns |
DELETE | /floor-plans/{id} | Remove a floor plan |
GET | /floor-plans/{id} | Get a floor plan |
PATCH | /floor-plans/{id} | Edit a floor plan |
PUT | /floor-plans/{id}/units | Place unidades on a floor plan |
GET | /handovers | List actas de entrega |
POST | /handovers | Open the acta de entrega of a unidad |
DELETE | /handovers/{id} | Cancel an acta that is not signed |
GET | /handovers/{id} | One acta: checklist by section, photos and casos |
PATCH | /handovers/{id} | Write the acta’s general notes |
POST | /handovers/{id}/attest | Confirm the owner’s identity in person |
POST | /handovers/{id}/casos | Open the post-venta casos of a signed acta |
PATCH | /handovers/{id}/items/{itemId} | Answer a checklist line |
POST | /handovers/{id}/media | Attach photos or videos to the walk |
GET | /handovers/{id}/pdf | Download the signed acta |
POST | /handovers/{id}/reopen | Reopen an acta that was sent, to correct it |
POST | /handovers/{id}/send | Send the acta to the owner to sign |
GET | /negocios | List negocios |
GET | /negocios/{id} | Get a negocio |
GET | /negocios/{id}/bank-approvals | A negocio’s bank approvals |
POST | /negocios/{id}/bank-approvals | Track a bank’s approval |
DELETE | /negocios/{id}/bank-approvals/{approvalId} | Stop tracking a bank |
PATCH | /negocios/{id}/bank-approvals/{approvalId} | Update a bank’s approval |
GET | /negocios/{id}/buyer-view | What the buyer can be told on WhatsApp |
GET | /negocios/{id}/cuotas/{number}/payment | How a cuota can be paid |
PATCH | /negocios/{id}/deadlines | Edit a negocio’s deadlines |
POST | /negocios/{id}/desistimiento | Record a desistimiento |
GET | /negocios/{id}/documents | A negocio’s document checklist |
GET | /negocios/{id}/documents/{documentId}/file | Download a checklist document |
POST | /negocios/{id}/documents/{documentId}/file | Upload a document onto a checklist item |
POST | /negocios/{id}/documents/{documentId}/review | Approve or reject a checklist document |
POST | /negocios/{id}/entrega | Record the entrega |
POST | /negocios/{id}/escritura | Record the escritura |
POST | /negocios/{id}/pie-plan | Split the pie into cuotas |
POST | /negocios/{id}/promesa | Record the promesa |
GET | /negocios/{id}/signatures | A negocio’s signing requests |
POST | /negocios/{id}/signatures | Send a negocio document to sign |
POST | /negocios/{id}/signatures/{signatureId}/cancel | Cancel a signing request |
GET | /negocios/{id}/signatures/{signatureId}/files/{file} | Download a signing file |
POST | /negocios/{id}/signatures/{signatureId}/resend | Send a new signing link |
GET | /negocios/{id}/statement | A negocio’s account statement |
GET | /negocios/{id}/statement/pdf | The account statement as a PDF |
POST | /negocios/{id}/statement/send | Send the account statement to the buyer |
GET | /postventa/report | Post-venta report by proyecto, partida, estado de garantía or etapa |
GET | /postventa/unit-owners | The unidades a contact owns |
PUT | /postventa/unit-owners | Register the owner of a unidad |
DELETE | /postventa/unit-owners/{id} | End an ownership |
GET | /price-lists | List lista de precios versions |
POST | /price-lists | Open a draft lista de precios |
DELETE | /price-lists/{id} | Discard a draft lista de precios |
GET | /price-lists/{id} | One lista de precios version, with its prices |
PATCH | /price-lists/{id} | Rename a draft lista de precios |
PATCH | /price-lists/{id}/entries | Set prices in a draft lista de precios |
POST | /price-lists/{id}/import | Price import steps 2–3: dry run, then load prices into a draft |
POST | /price-lists/{id}/publish | Publish a lista de precios version |
POST | /price-lists/import/columns | Price import step 1: read a file’s columns |
GET | /project-listings | List portal anuncios (Portal Inmobiliario, Yapo) and their proyecto |
POST | /project-listings | Map a Portal Inmobiliario anuncio to a proyecto |
PATCH | /project-listings/{id} | Map or unmap a Portal Inmobiliario anuncio |
GET | /projects | List proyectos |
POST | /projects | Add a proyecto |
DELETE | /projects/{id} | Remove a proyecto |
GET | /projects/{id} | One proyecto, with its sala de ventas and tipologías |
PATCH | /projects/{id} | Edit a proyecto |
GET | /projects/{id}/document-requirements | Get a proyecto’s document checklist |
PUT | /projects/{id}/document-requirements | Set a proyecto’s document checklist |
DELETE | /projects/{id}/entrega-checklist | Back to the default entrega checklist |
GET | /projects/{id}/entrega-checklist | The proyecto’s entrega checklist |
PUT | /projects/{id}/entrega-checklist | Set the proyecto’s own entrega checklist |
GET | /projects/{id}/floor-plans | List a proyecto’s floor plans |
POST | /projects/{id}/floor-plans | Add a floor plan to a proyecto |
GET | /projects/{id}/marketing-kit | Read a proyecto’s marketing kit |
PATCH | /projects/{id}/marketing-kit | Edit a proyecto’s marketing kit |
GET | /projects/{id}/marketing-kit/audience | Who a kit broadcast would reach |
POST | /projects/{id}/marketing-kit/broadcast | Send a proyecto’s kit message by WhatsApp |
POST | /projects/{id}/marketing-kit/generate | Generate a proyecto’s marketing kit |
GET | /projects/{id}/members | List the ejecutivos of a proyecto |
POST | /projects/{id}/members | Assign an ejecutivo to a proyecto |
DELETE | /projects/{id}/members/{userId} | Unassign an ejecutivo from a proyecto |
GET | /projects/{id}/milestone-terms | Get a proyecto’s milestone deadlines |
PUT | /projects/{id}/milestone-terms | Set a proyecto’s milestone deadlines |
GET | /projects/{id}/obra-updates | A proyecto’s obra progress posts |
POST | /projects/{id}/obra-updates | Post an obra progress update |
DELETE | /projects/{id}/obra-updates/{updateId} | Remove an obra post |
POST | /projects/{id}/obra-updates/{updateId}/announce | Tell the proyecto’s buyers about an obra post |
POST | /projects/{id}/obra-updates/{updateId}/photos | Add a photo to an obra post |
DELETE | /projects/{id}/obra-updates/{updateId}/photos/{index} | Remove a photo from an obra post |
GET | /projects/{id}/obra-updates/{updateId}/photos/{index} | Read an obra photo |
GET | /projects/{id}/pie-terms | Get a proyecto’s cuota reminders |
PUT | /projects/{id}/pie-terms | Set a proyecto’s cuota reminders |
GET | /projects/{id}/publication-readiness | Check a proyecto before publishing it to Portal Inmobiliario |
GET | /projects/{id}/publications | List a proyecto’s Portal Inmobiliario anuncios |
POST | /projects/{id}/publications | Publish a proyecto and its tipologías to Portal Inmobiliario |
DELETE | /projects/{id}/publications/{publicationId} | Close a proyecto’s listing on Portal Inmobiliario |
GET | /projects/{id}/reserva-terms | Get a proyecto’s reserva terms |
PUT | /projects/{id}/reserva-terms | Set a proyecto’s reserva terms |
DELETE | /projects/{id}/signing-templates/{kind} | Reset a proyecto’s signing template |
GET | /projects/{id}/signing-templates/{kind} | Get a proyecto’s signing template |
PUT | /projects/{id}/signing-templates/{kind} | Set a proyecto’s signing template |
GET | /projects/{id}/toctoc | A proyecto’s TocToc publishing payload and state |
PUT | /projects/{id}/toctoc | Record where a proyecto stands on TocToc |
GET | /projects/{id}/whatsapp-links | Get the tracked WhatsApp links of a proyecto |
GET | /real-estate-offers | List the unit offers sent to old leads |
GET | /real-estate-offers/settings | Read the unit-offer settings |
PUT | /real-estate-offers/settings | Change the unit-offer settings |
GET | /real-estate-reports/projects | Developer report per proyecto |
GET | /reservas | List reservas |
GET | /reservas/{id} | Get a reserva |
POST | /reservas/{id}/cancel | Release a reserva’s hold |
GET | /reservas/{id}/payment | How a reserva can be paid |
GET | /toctoc-connection | The TocToc lead door of the workspace |
POST | /toctoc-connection/token | Create or rotate the TocToc lead door token |
GET | /toctoc-listings | List TocToc publications and their proyecto |
POST | /toctoc-listings | Map a TocToc publication code to a proyecto |
PATCH | /toctoc-listings/{id} | Map or unmap a TocToc publication |
GET | /unit-models | List tipologías |
POST | /unit-models | Add a tipología to a proyecto |
DELETE | /unit-models/{id} | Remove a tipología |
GET | /unit-models/{id} | One tipología |
PATCH | /unit-models/{id} | Edit a tipología |
GET | /units | List unidades (a proyecto’s stock) |
POST | /units | Add a unidad by hand |
DELETE | /units/{id} | Remove a unidad |
GET | /units/{id} | One unidad |
PATCH | /units/{id} | Edit a unidad |
GET | /units/{id}/price-history | A unidad’s price in every published lista de precios |
POST | /units/{id}/release-fields | Let a unidad’s protected fields follow the import again |
POST | /units/import | Import steps 2–3: dry run, then load a proyecto’s unidades |
POST | /units/import/columns | Import step 1: read a stock file’s columns |
DELETE /case-assignments/{id}
Cancel an assignment
The link stops working at once (it answers 404), the observaciones go back to the caso unassigned, and the contratista is told. A finished assignment cannot be cancelled (409). Requires tickets:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/case-assignments/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000a21",
"ticket_id": "0199e3a0-0000-7000-8000-000000000a01",
"contratista_id": "0199e3a0-0000-7000-8000-000000000a11",
"status": "cancelled",
"brief": "Revisar la filtración detrás del WC.",
"owner_window": "Lunes a viernes de 9 a 18",
"appointment_id": null,
"visit_starts_at": null,
"notified_at": "2026-10-20T12:01:00.000Z",
"notify_error": null,
"accepted_at": null,
"scheduled_at": null,
"done_at": null,
"declined_at": null,
"decline_reason": null,
"completion_notes": null,
"created_at": "2026-10-20T12:00:00.000Z",
"contratista_name": "Gasfitería Araucanía",
"contratista_trade": "gasfitería",
"contratista_whatsapp": "+56912345678",
"observation_ids": [
"0199e3a0-0000-7000-8000-000000000b01"
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /case-assignments/{id}/link
A fresh link for an assignment, optionally re-sent
Mints a new 30-day link for the assignment (the old one keeps working until it expires or the assignment is cancelled). With resend: true it is also sent to the contratista by WhatsApp. 409 when the assignment was cancelled. Requires tickets:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/case-assignments/<id>/link \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"resend": true
}'Ejemplo de respuesta (200)
{
"data": {
"link": "https://app.example.com/caso/eyJhbGciOi…",
"notified": true,
"notify_error": null
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /channel-commissions
List channel commissions
Commissions and rewards owed to corredores and referidores, from pending to paid. status=due is the payout queue. Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Refused (403) to a caller whose role narrows proyectos: the channel is managed by whoever sees every proyecto.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
partner_id | query | uuid | no | |
lead_id | query | uuid | no | |
status | query | pending \ | due \ | paid \ |
limit | query | integer | no | ≥ 1, ≤ 200 |
offset | query | integer | null | no | ≥ 0 |
curl https://api.vitrinadev.com/api/v1/channel-commissions \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000703",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"partner_id": "0199e3a0-0000-7000-8000-000000000701",
"claim_id": "0199e3a0-0000-7000-8000-000000000702",
"lead_id": "0199e3a0-0000-7000-8000-000000000704",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"basis": "percent",
"rate_value": 2,
"currency": null,
"milestone": "escritura",
"status": "pending",
"base_amount": null,
"amount": null,
"due_at": null,
"paid_at": null,
"paid_reference": null,
"cancelled_reason": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
]
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /channel-commissions/{id}/cancel
Cancel a commission
For a desistimiento or an agreement that no longer holds. A paid commission cannot be cancelled (409 CONFLICT, details.code COMMISSION_FINAL). Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Refused (403) to a caller whose role narrows proyectos: the channel is managed by whoever sees every proyecto.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/channel-commissions/<id>/cancel \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"reason": "Desistimiento"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000703",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"partner_id": "0199e3a0-0000-7000-8000-000000000701",
"claim_id": "0199e3a0-0000-7000-8000-000000000702",
"lead_id": "0199e3a0-0000-7000-8000-000000000704",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"basis": "percent",
"rate_value": 2,
"currency": null,
"milestone": "escritura",
"status": "cancelled",
"base_amount": null,
"amount": null,
"due_at": null,
"paid_at": null,
"paid_reference": null,
"cancelled_reason": "Desistimiento",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /channel-commissions/{id}/pay
Mark a commission paid
Closes the payout of a due commission with the transfer reference. 409 CONFLICT (details.code COMMISSION_NOT_DUE) when the milestone was not reached or it is already paid; 400 when it has no amount yet. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Refused (403) to a caller whose role narrows proyectos: the channel is managed by whoever sees every proyecto.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/channel-commissions/<id>/pay \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"reference": "TRF-20261215-0042"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000703",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"partner_id": "0199e3a0-0000-7000-8000-000000000701",
"claim_id": "0199e3a0-0000-7000-8000-000000000702",
"lead_id": "0199e3a0-0000-7000-8000-000000000704",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"basis": "percent",
"rate_value": 2,
"currency": "UF",
"milestone": "escritura",
"status": "paid",
"base_amount": null,
"amount": 70,
"due_at": null,
"paid_at": "2026-12-15T12:00:00.000Z",
"paid_reference": "TRF-20261215-0042",
"cancelled_reason": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /channel-commissions/milestones
Record that a lead’s negocio reached a milestone
Every open commission of the lead whose agreed milestone is this one (or an earlier one) falls due. A percentage is computed on base_amount (default: the lead's value); due with no value yet, it takes its amount when the milestone is recorded again with one. Idempotent. The negocio flow records its milestones itself; this route is the manual door. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Refused (403) to a caller whose role narrows proyectos: the channel is managed by whoever sees every proyecto.
curl -X POST https://api.vitrinadev.com/api/v1/channel-commissions/milestones \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"lead_id": "0199e3a0-0000-7000-8000-000000000704",
"milestone": "escritura",
"base_amount": 3500,
"base_currency": "UF"
}'Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000703",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"partner_id": "0199e3a0-0000-7000-8000-000000000701",
"claim_id": "0199e3a0-0000-7000-8000-000000000702",
"lead_id": "0199e3a0-0000-7000-8000-000000000704",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"basis": "percent",
"rate_value": 2,
"currency": "UF",
"milestone": "escritura",
"status": "due",
"base_amount": 3500,
"amount": 70,
"due_at": "2026-12-01T12:00:00.000Z",
"paid_at": null,
"paid_reference": null,
"cancelled_reason": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
]
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /channel-partners
List corredores externos and referidores
The inmobiliaria's channel: brokers outside the company and referrers, each with the personal code of their link and the commission agreed. Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Refused (403) to a caller whose role narrows proyectos: the channel is managed by whoever sees every proyecto.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
kind | query | broker \ | referrer | no |
status | query | active \ | paused | no |
q | query | string | no | máx. 100 |
limit | query | integer | no | ≥ 1, ≤ 200 |
offset | query | integer | null | no | ≥ 0 |
curl https://api.vitrinadev.com/api/v1/channel-partners \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000701",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"kind": "broker",
"name": "María López",
"company": "López Propiedades",
"email": "[email protected]",
"phone": "+56912345678",
"code": "marialopez4k2x",
"referral_param": "ref=marialopez4k2x",
"status": "active",
"protection_days": 90,
"commission_basis": "percent",
"commission_value": 2,
"commission_currency": null,
"commission_milestone": "escritura",
"notes": null,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"active_claim_count": 3,
"due_commission_count": 1
}
]
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /channel-partners
Add a corredor externo or referidor
Creates the partner and their personal code. Append ref=<code> to a proyecto page or form URL: a buyer who submits the proyecto form through it is credited to the partner and protected for protection_days (a second partner claiming the same buyer on the same proyecto inside the window is refused). The commission falls due when the negocio reaches commission_milestone. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Refused (403) to a caller whose role narrows proyectos: the channel is managed by whoever sees every proyecto.
curl -X POST https://api.vitrinadev.com/api/v1/channel-partners \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"kind": "broker",
"name": "María López",
"company": "López Propiedades",
"protection_days": 90,
"commission_basis": "percent",
"commission_value": 2,
"commission_milestone": "escritura"
}'Ejemplo de respuesta (201)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000701",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"kind": "broker",
"name": "María López",
"company": "López Propiedades",
"email": "[email protected]",
"phone": "+56912345678",
"code": "marialopez4k2x",
"referral_param": "ref=marialopez4k2x",
"status": "active",
"protection_days": 90,
"commission_basis": "percent",
"commission_value": 2,
"commission_currency": null,
"commission_milestone": "escritura",
"notes": null,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
GET /channel-partners/{id}
One corredor externo or referidor
Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Refused (403) to a caller whose role narrows proyectos: the channel is managed by whoever sees every proyecto.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/channel-partners/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000701",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"kind": "broker",
"name": "María López",
"company": "López Propiedades",
"email": "[email protected]",
"phone": "+56912345678",
"code": "marialopez4k2x",
"referral_param": "ref=marialopez4k2x",
"status": "active",
"protection_days": 90,
"commission_basis": "percent",
"commission_value": 2,
"commission_currency": null,
"commission_milestone": "escritura",
"notes": null,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /channel-partners/{id}
Edit a corredor externo or referidor
Changes their data, protection window or commission terms, or pauses them (status). New terms apply to buyers credited from now on: the commission of a buyer already credited keeps the terms it was promised under. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Refused (403) to a caller whose role narrows proyectos: the channel is managed by whoever sees every proyecto.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X PATCH https://api.vitrinadev.com/api/v1/channel-partners/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"protection_days": 120
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000701",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"kind": "broker",
"name": "María López",
"company": "López Propiedades",
"email": "[email protected]",
"phone": "+56912345678",
"code": "marialopez4k2x",
"referral_param": "ref=marialopez4k2x",
"status": "active",
"protection_days": 90,
"commission_basis": "percent",
"commission_value": 2,
"commission_currency": null,
"commission_milestone": "escritura",
"notes": null,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /channel-partners/{id}/claims
The buyers a partner brought
Their claims, newest first, including the refused ones (a claim lost to an earlier one still inside its window). Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Refused (403) to a caller whose role narrows proyectos: the channel is managed by whoever sees every proyecto.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
status | query | active \ | refused | no |
limit | query | integer | no | ≥ 1, ≤ 200 |
offset | query | integer | null | no | ≥ 0 |
curl https://api.vitrinadev.com/api/v1/channel-partners/<id>/claims \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000702",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"partner_id": "0199e3a0-0000-7000-8000-000000000701",
"contact_id": "0199e3a0-0000-7000-8000-000000000705",
"lead_id": "0199e3a0-0000-7000-8000-000000000704",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"status": "active",
"claimed_at": "2026-10-20T12:00:00.000Z",
"protected_until": "2027-01-18T12:00:00.000Z",
"refused_by_claim_id": null,
"created_at": "2026-10-20T12:00:00.000Z"
}
]
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /channel-partners/{id}/claims
Credit a lead to a corredor or referidor
Registers by hand that the lead's buyer was brought by the partner (a buyer who reached WhatsApp instead of the form). The buyer is protected for the partner's window. The same partner claiming again inside their window changes nothing (200). A different partner claiming the same buyer on the same proyecto inside someone's window is refused with 409 CONFLICT whose details.code is LEAD_PROTECTED and carries protected_until and protected_by_partner_id. A paused partner cannot claim (400). Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Refused (403) to a caller whose role narrows proyectos: the channel is managed by whoever sees every proyecto.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/channel-partners/<id>/claims \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"lead_id": "0199e3a0-0000-7000-8000-000000000704"
}'Ejemplo de respuesta (200)
{
"data": {
"outcome": "already_credited",
"claim": {
"id": "0199e3a0-0000-7000-8000-000000000702",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"partner_id": "0199e3a0-0000-7000-8000-000000000701",
"contact_id": "0199e3a0-0000-7000-8000-000000000705",
"lead_id": "0199e3a0-0000-7000-8000-000000000704",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"status": "active",
"claimed_at": "2026-10-20T12:00:00.000Z",
"protected_until": "2027-01-18T12:00:00.000Z",
"refused_by_claim_id": null,
"created_at": "2026-10-20T12:00:00.000Z"
},
"commission": {
"id": "0199e3a0-0000-7000-8000-000000000703",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"partner_id": "0199e3a0-0000-7000-8000-000000000701",
"claim_id": "0199e3a0-0000-7000-8000-000000000702",
"lead_id": "0199e3a0-0000-7000-8000-000000000704",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"basis": "percent",
"rate_value": 2,
"currency": null,
"milestone": "escritura",
"status": "pending",
"base_amount": null,
"amount": null,
"due_at": null,
"paid_at": null,
"paid_reference": null,
"cancelled_reason": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
}
}Responde: 200 · 201 · 400 · 401 · 403 · 404 · 409 · 429
GET /cobranza
Overdue pie cuotas
Every cuota past its due day with money still owed, oldest first, with the negocio, buyer, proyecto, ejecutivo and days overdue. Filter by project_id. Requires payments:read. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
project_id | query | uuid[] | no | |
limit | query | integer | no | ≥ 1, ≤ 200 |
offset | query | integer | null | no | ≥ 0 |
curl https://api.vitrinadev.com/api/v1/cobranza \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"display_id": "NG-3",
"buyer_name": "Camila Rojas",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"days_overdue": 4,
"cuota": {
"number": 1,
"due_on": "2026-11-20",
"amount": 58.5,
"currency": "UF",
"amount_clp": 2312629,
"obligation_id": "0199e3a0-0000-7000-8000-000000000c21",
"paid_clp": 0,
"outstanding_clp": 2312629,
"state": "overdue",
"is_overdue": true
}
}
],
"meta": {
"pagination": {
"limit": 100,
"offset": 0
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /contratistas
List contratistas
The external companies and technicians that repair post-venta casos. Filters: q (name or trade), trade, active. Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
q | query | string | no | máx. 100 |
trade | query | string | no | máx. 120 |
active | query | boolean | no | |
limit | query | integer | no | ≥ 1, ≤ 200 |
offset | query | integer | null | no | ≥ 0 |
curl https://api.vitrinadev.com/api/v1/contratistas \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000a11",
"name": "Gasfitería Araucanía",
"trade": "gasfitería",
"whatsapp": "+56912345678",
"email": null,
"zones": [
"Ñuñoa",
"Providencia"
],
"notes": null,
"active": true,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
],
"meta": {
"pagination": {
"total": 1,
"limit": 50,
"offset": 0
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /contratistas
Add a contratista
Names are unique among the workspace’s live contratistas (409 otherwise). whatsapp is stored as E.164; it is where the work and the link are sent. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
curl -X POST https://api.vitrinadev.com/api/v1/contratistas \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Gasfitería Araucanía",
"trade": "gasfitería",
"whatsapp": "+56912345678",
"zones": [
"Ñuñoa",
"Providencia"
]
}'Ejemplo de respuesta (201)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000a11",
"name": "Gasfitería Araucanía",
"trade": "gasfitería",
"whatsapp": "+56912345678",
"email": null,
"zones": [
"Ñuñoa",
"Providencia"
],
"notes": null,
"active": true,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /contratistas/{id}
Remove a contratista
Soft delete. Assignments already sent keep working until they finish. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/contratistas/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Responde: 204 · 400 · 401 · 403 · 404 · 409 · 429
GET /contratistas/{id}
One contratista
Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/contratistas/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000a11",
"name": "Gasfitería Araucanía",
"trade": "gasfitería",
"whatsapp": "+56912345678",
"email": null,
"zones": [
"Ñuñoa",
"Providencia"
],
"notes": null,
"active": true,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /contratistas/{id}
Edit a contratista
Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X PATCH https://api.vitrinadev.com/api/v1/contratistas/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"active": false
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000a11",
"name": "Gasfitería Araucanía",
"trade": "gasfitería",
"whatsapp": "+56912345678",
"email": null,
"zones": [
"Ñuñoa",
"Providencia"
],
"notes": null,
"active": true,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /cotizacion-discount-approvals
The approver’s queue of discount requests
Requests with the cotización, buyer and proyecto they are about, newest first. Default status=pending. Narrowed to the caller’s proyectos (a jefe de sala sees their sala’s; a gerente all). Requires cotizacion_discount:approve. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
status | query | pending \ | approved \ | refused \ |
limit | query | integer | no | ≥ 1, ≤ 200 |
offset | query | integer | null | no | ≥ 0 |
curl https://api.vitrinadev.com/api/v1/cotizacion-discount-approvals \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000a01",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"status": "pending",
"requested_by": "0199e3a0-0000-7000-8000-0000000000bb",
"requested_at": "2026-10-20T12:00:00.000Z",
"note": "Cliente cierra hoy si llegamos al 6 %.",
"requested_percent": 6,
"limit_percent": 3,
"currency": "UF",
"list_total": 3510,
"discount_total": 210.6,
"total": 3299.4,
"decided_by": null,
"decided_at": null,
"decision_reason": null,
"cotizacion_display_id": "CZ-12",
"cotizacion_status": "draft",
"buyer_name": "Camila Rojas",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb"
}
],
"meta": {
"pagination": {
"total": 1,
"limit": 50,
"offset": 0
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /cotizacion-discount-approvals/{id}/decision
Approve or refuse a discount request
approve makes the cotización sendable for any discount up to the one asked; refuse needs a reason, which returns to the ejecutivo with the cotización. Terminal: a decided request cannot be decided again (409 approval_not_pending). Nobody decides their own request (409 self_decision). The ejecutivo is told in the bell and both outcomes are audited. 404 when the cotización is outside the caller’s proyectos. Requires cotizacion_discount:approve alone. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
decision | approve \ | refuse | sí |
reason | string | — | mín. 1, máx. 1000 |
curl -X POST https://api.vitrinadev.com/api/v1/cotizacion-discount-approvals/<id>/decision \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"decision": "approve"
}'Ejemplo de respuesta (200)
{
"data": {
"approval": {
"id": "0199e3a0-0000-7000-8000-000000000a01",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"status": "approved",
"requested_by": "0199e3a0-0000-7000-8000-0000000000bb",
"requested_at": "2026-10-20T12:00:00.000Z",
"note": "Cliente cierra hoy si llegamos al 6 %.",
"requested_percent": 6,
"limit_percent": 3,
"currency": "UF",
"list_total": 3510,
"discount_total": 210.6,
"total": 3299.4,
"decided_by": "0199e3a0-0000-7000-8000-0000000000cc",
"decided_at": "2026-10-20T12:10:00.000Z",
"decision_reason": null
},
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"cotizacion_display_id": "CZ-12"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /cotizaciones
List cotizaciones
Newest first, without lines or financing (GET /cotizaciones/\{id\}). Filters: lead_id, project_id, status. Requires leads:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches the cotizaciones of their proyectos and leads; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
lead_id | query | uuid | no | |
project_id | query | uuid[] | no | |
status | query | draft \ | sent \ | accepted \ |
limit | query | integer | no | ≥ 1, ≤ 200 |
offset | query | integer | null | no | ≥ 0 |
curl https://api.vitrinadev.com/api/v1/cotizaciones \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000901",
"display_id": "CZ-12",
"status": "sent",
"buyer_name": "Camila Rojas",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": null,
"conversation_id": null,
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"price_list_version_id": "0199e3a0-0000-7000-8000-000000000501",
"price_list_version_number": 2,
"price_list_superseded": false,
"currency": "UF",
"uf_value_clp": 39532.12,
"uf_value_date": "2026-10-20",
"valid_until": "2026-10-27",
"discount_type": "percent",
"discount_value": 0,
"list_total": 3510,
"line_discount_total": 0,
"global_discount_total": 0,
"discount_total": 0,
"total": 3510,
"discount_percent": 0,
"notes": null,
"template_version": "cotizacion/2026-10",
"presentation": {
"ejecutivo": {
"name": "Valentina Soto",
"phone": "+56987654321",
"email": "[email protected]"
},
"sala": {
"name": "Sala Los Aromos",
"address": "Av. Vicuña Mackenna 9000, La Florida",
"hours": "Lunes a viernes 10:00–19:00 h · Sábados 10:00–14:00 h"
},
"image_url": null
},
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:05:00.000Z",
"sent_at": "2026-10-20T12:05:00.000Z",
"accepted_at": null,
"rejected_at": null,
"voided_at": null,
"voided_reason": null,
"is_expired": false
}
],
"meta": {
"pagination": {
"total": 1,
"limit": 50,
"offset": 0
},
"uf_value": {
"clp": 39532.12,
"date": "2026-10-20"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /cotizaciones
Build a cotización draft
Builds a draft from unidades: a departamento or casa plus estacionamientos and bodegas, all of ONE proyecto and disponible. Prices come from the proyecto’s current published lista de precios (or price_list_version_id), which the cotización PINS: a newer list never rewrites it. Currency UF (default) or CLP; per-line and global discounts; validity (valid_until or valid_days, default 7); and the financing block (pie %, pie in cuotas, crédito hipotecario → dividendo and renta requerida; omitted → defaults, null → none). Only a name is needed for the buyer, never a RUT. 404 for a unidad or lead outside the caller’s proyectos; 409 unit_not_available, project_has_no_price_list; 400 unit_not_priced. Requires leads:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches the cotizaciones of their proyectos and leads; anything else is a 404.
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
lead_id | string | null | — | |
buyer_name | string | null | — | mín. 1, máx. 200 |
lines | object[] | sí | |
currency | UF \ | CLP | — |
valid_until | string | null | — | patrón ^\d{4}-\d{2}-\d{2}$ |
valid_days | integer | null | — | ≥ 1, ≤ 365 |
discount | object | null | — | |
financing | object | null | — | |
notes | string | null | — | máx. 2000 |
price_list_version_id | string | null | — |
curl -X POST https://api.vitrinadev.com/api/v1/cotizaciones \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"lines": [
{
"unit_id": "0199e3a0-0000-7000-8000-000000000401"
},
{
"unit_id": "0199e3a0-0000-7000-8000-000000000402"
},
{
"unit_id": "0199e3a0-0000-7000-8000-000000000403"
}
],
"currency": "UF",
"valid_days": 7,
"discount": {
"type": "percent",
"value": 2
},
"financing": {
"pie_percent": 20,
"pie_installments": 36,
"credit_years": 30,
"credit_rate_annual": 4.5
}
}'Ejemplo de respuesta (201)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000901",
"display_id": "CZ-12",
"status": "draft",
"buyer_name": "Camila Rojas",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": null,
"conversation_id": null,
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"price_list_version_id": "0199e3a0-0000-7000-8000-000000000501",
"price_list_version_number": 2,
"price_list_superseded": false,
"currency": "UF",
"uf_value_clp": 39532.12,
"uf_value_date": "2026-10-20",
"valid_until": "2026-10-27",
"discount_type": "percent",
"discount_value": 0,
"list_total": 3510,
"line_discount_total": 0,
"global_discount_total": 0,
"discount_total": 0,
"total": 3510,
"discount_percent": 0,
"notes": null,
"template_version": "cotizacion/2026-10",
"presentation": {
"ejecutivo": {
"name": "Valentina Soto",
"phone": "+56987654321",
"email": "[email protected]"
},
"sala": {
"name": "Sala Los Aromos",
"address": "Av. Vicuña Mackenna 9000, La Florida",
"hours": "Lunes a viernes 10:00–19:00 h · Sábados 10:00–14:00 h"
},
"image_url": null
},
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:05:00.000Z",
"sent_at": null,
"accepted_at": null,
"rejected_at": null,
"voided_at": null,
"voided_reason": null,
"is_expired": false,
"total_uf": 3510,
"total_clp": 138760000,
"lines": [
{
"id": "0199e3a0-0000-7000-8000-000000000902",
"position": 0,
"offering_type": "property",
"offering_id": "0199e3a0-0000-7000-8000-000000000401",
"kind": "departamento",
"label": "Departamento 1203 · 3D2B 78 m²",
"offering_number": "1203",
"detail": {
"model_name": "3D2B 78 m²",
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"floor": 12,
"orientation": "norte"
},
"quantity": 1,
"unit_price": 3310,
"discount_type": "percent",
"discount_value": 0,
"list_total": 3310,
"discount_total": 0,
"total": 3310
},
{
"id": "0199e3a0-0000-7000-8000-000000000902",
"position": 1,
"offering_type": "property",
"offering_id": "0199e3a0-0000-7000-8000-000000000402",
"kind": "estacionamiento",
"label": "Estacionamiento 45",
"offering_number": "45",
"detail": {},
"quantity": 1,
"unit_price": 200,
"discount_type": "percent",
"discount_value": 0,
"list_total": 200,
"discount_total": 0,
"total": 200
}
],
"financing": {
"pie_percent": 20,
"pie_amount": 702,
"pie_installments": 36,
"pie_installment_amount": 19.5,
"credit_amount": 2808,
"credit_years": 30,
"credit_rate_annual": 4.5,
"monthly_payment": 14.23,
"monthly_payment_clp": 562600,
"income_ratio": 0.25,
"required_income_clp": 2250400
},
"sends": []
},
"meta": {
"uf_value": {
"clp": 39532.12,
"date": "2026-10-20"
}
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /cotizaciones/{id}
Discard a cotización draft
Drafts only: a sent cotización is a record and cannot be deleted (409 cotizacion_not_draft). Requires leads:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches the cotizaciones of their proyectos and leads; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/cotizaciones/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000901",
"deleted": true
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /cotizaciones/{id}
Get a cotización
The offer with its lines, financing block and every send. price_list_superseded tells a draft it must be re-priced. Requires leads:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches the cotizaciones of their proyectos and leads; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/cotizaciones/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000901",
"display_id": "CZ-12",
"status": "sent",
"buyer_name": "Camila Rojas",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": null,
"conversation_id": null,
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"price_list_version_id": "0199e3a0-0000-7000-8000-000000000501",
"price_list_version_number": 2,
"price_list_superseded": false,
"currency": "UF",
"uf_value_clp": 39532.12,
"uf_value_date": "2026-10-20",
"valid_until": "2026-10-27",
"discount_type": "percent",
"discount_value": 0,
"list_total": 3510,
"line_discount_total": 0,
"global_discount_total": 0,
"discount_total": 0,
"total": 3510,
"discount_percent": 0,
"notes": null,
"template_version": "cotizacion/2026-10",
"presentation": {
"ejecutivo": {
"name": "Valentina Soto",
"phone": "+56987654321",
"email": "[email protected]"
},
"sala": {
"name": "Sala Los Aromos",
"address": "Av. Vicuña Mackenna 9000, La Florida",
"hours": "Lunes a viernes 10:00–19:00 h · Sábados 10:00–14:00 h"
},
"image_url": null
},
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:05:00.000Z",
"sent_at": "2026-10-20T12:05:00.000Z",
"accepted_at": null,
"rejected_at": null,
"voided_at": null,
"voided_reason": null,
"is_expired": false,
"total_uf": 3510,
"total_clp": 138760000,
"lines": [
{
"id": "0199e3a0-0000-7000-8000-000000000902",
"position": 0,
"offering_type": "property",
"offering_id": "0199e3a0-0000-7000-8000-000000000401",
"kind": "departamento",
"label": "Departamento 1203 · 3D2B 78 m²",
"offering_number": "1203",
"detail": {
"model_name": "3D2B 78 m²",
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"floor": 12,
"orientation": "norte"
},
"quantity": 1,
"unit_price": 3310,
"discount_type": "percent",
"discount_value": 0,
"list_total": 3310,
"discount_total": 0,
"total": 3310
},
{
"id": "0199e3a0-0000-7000-8000-000000000902",
"position": 1,
"offering_type": "property",
"offering_id": "0199e3a0-0000-7000-8000-000000000402",
"kind": "estacionamiento",
"label": "Estacionamiento 45",
"offering_number": "45",
"detail": {},
"quantity": 1,
"unit_price": 200,
"discount_type": "percent",
"discount_value": 0,
"list_total": 200,
"discount_total": 0,
"total": 200
}
],
"financing": {
"pie_percent": 20,
"pie_amount": 702,
"pie_installments": 36,
"pie_installment_amount": 19.5,
"credit_amount": 2808,
"credit_years": 30,
"credit_rate_annual": 4.5,
"monthly_payment": 14.23,
"monthly_payment_clp": 562600,
"income_ratio": 0.25,
"required_income_clp": 2250400
},
"sends": [
{
"id": "0199e3a0-0000-7000-8000-000000000902",
"channel": "whatsapp",
"recipient_hint": "+56•••••4567",
"sent_by": "0199e3a0-0000-7000-8000-0000000000bb",
"sent_by_kind": "ui_member",
"sent_at": "2026-10-20T12:05:00.000Z"
}
]
},
"meta": {
"uf_value": {
"clp": 39532.12,
"date": "2026-10-20"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /cotizaciones/{id}
Edit a cotización draft
Drafts only (409 cotizacion_not_draft once sent). Any field of the create body; the figures are recomputed. A draft keeps the lista de precios version it pinned unless refresh_prices: true re-prices it on the proyecto’s current list. Requires leads:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches the cotizaciones of their proyectos and leads; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
lead_id | string | null | — | |
buyer_name | string | null | — | mín. 1, máx. 200 |
lines | object[] | — | |
currency | UF \ | CLP | — |
valid_until | string | null | — | patrón ^\d{4}-\d{2}-\d{2}$ |
valid_days | integer | null | — | ≥ 1, ≤ 365 |
discount | object | null | — | |
financing | object | null | — | |
notes | string | null | — | máx. 2000 |
price_list_version_id | string | null | — | |
refresh_prices | boolean | — |
curl -X PATCH https://api.vitrinadev.com/api/v1/cotizaciones/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"discount": {
"type": "percent",
"value": 3
},
"refresh_prices": true
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000901",
"display_id": "CZ-12",
"status": "draft",
"buyer_name": "Camila Rojas",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": null,
"conversation_id": null,
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"price_list_version_id": "0199e3a0-0000-7000-8000-000000000501",
"price_list_version_number": 2,
"price_list_superseded": false,
"currency": "UF",
"uf_value_clp": 39532.12,
"uf_value_date": "2026-10-20",
"valid_until": "2026-10-27",
"discount_type": "percent",
"discount_value": 0,
"list_total": 3510,
"line_discount_total": 0,
"global_discount_total": 0,
"discount_total": 0,
"total": 3510,
"discount_percent": 0,
"notes": null,
"template_version": "cotizacion/2026-10",
"presentation": {
"ejecutivo": {
"name": "Valentina Soto",
"phone": "+56987654321",
"email": "[email protected]"
},
"sala": {
"name": "Sala Los Aromos",
"address": "Av. Vicuña Mackenna 9000, La Florida",
"hours": "Lunes a viernes 10:00–19:00 h · Sábados 10:00–14:00 h"
},
"image_url": null
},
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:05:00.000Z",
"sent_at": null,
"accepted_at": null,
"rejected_at": null,
"voided_at": null,
"voided_reason": null,
"is_expired": false,
"total_uf": 3510,
"total_clp": 138760000,
"lines": [
{
"id": "0199e3a0-0000-7000-8000-000000000902",
"position": 0,
"offering_type": "property",
"offering_id": "0199e3a0-0000-7000-8000-000000000401",
"kind": "departamento",
"label": "Departamento 1203 · 3D2B 78 m²",
"offering_number": "1203",
"detail": {
"model_name": "3D2B 78 m²",
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"floor": 12,
"orientation": "norte"
},
"quantity": 1,
"unit_price": 3310,
"discount_type": "percent",
"discount_value": 0,
"list_total": 3310,
"discount_total": 0,
"total": 3310
},
{
"id": "0199e3a0-0000-7000-8000-000000000902",
"position": 1,
"offering_type": "property",
"offering_id": "0199e3a0-0000-7000-8000-000000000402",
"kind": "estacionamiento",
"label": "Estacionamiento 45",
"offering_number": "45",
"detail": {},
"quantity": 1,
"unit_price": 200,
"discount_type": "percent",
"discount_value": 0,
"list_total": 200,
"discount_total": 0,
"total": 200
}
],
"financing": {
"pie_percent": 20,
"pie_amount": 702,
"pie_installments": 36,
"pie_installment_amount": 19.5,
"credit_amount": 2808,
"credit_years": 30,
"credit_rate_annual": 4.5,
"monthly_payment": 14.23,
"monthly_payment_clp": 562600,
"income_ratio": 0.25,
"required_income_clp": 2250400
},
"sends": []
},
"meta": {
"uf_value": {
"clp": 39532.12,
"date": "2026-10-20"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /cotizaciones/{id}/discount-approval
Where a cotización’s discount stands against the caller’s limit
The caller’s role limit (limit_percent, null = none), the cotización’s effective discount_percent, whether it exceeds_limit, the highest discount an approval has allowed (approved_percent), whether the caller can_send it as it stands, the open request (pending) and every request (approvals, newest first, with who decided and why). A refusal returns the cotización to the ejecutivo with its decision_reason. Requires leads:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/cotizaciones/<id>/discount-approval \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"limit_percent": 3,
"discount_percent": 6,
"exceeds_limit": true,
"approved_percent": null,
"can_send": false,
"pending": {
"id": "0199e3a0-0000-7000-8000-000000000a01",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"status": "pending",
"requested_by": "0199e3a0-0000-7000-8000-0000000000bb",
"requested_at": "2026-10-20T12:00:00.000Z",
"note": "Cliente cierra hoy si llegamos al 6 %.",
"requested_percent": 6,
"limit_percent": 3,
"currency": "UF",
"list_total": 3510,
"discount_total": 210.6,
"total": 3299.4,
"decided_by": null,
"decided_at": null,
"decision_reason": null
},
"approvals": [
{
"id": "0199e3a0-0000-7000-8000-000000000a01",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"status": "pending",
"requested_by": "0199e3a0-0000-7000-8000-0000000000bb",
"requested_at": "2026-10-20T12:00:00.000Z",
"note": "Cliente cierra hoy si llegamos al 6 %.",
"requested_percent": 6,
"limit_percent": 3,
"currency": "UF",
"list_total": 3510,
"discount_total": 210.6,
"total": 3299.4,
"decided_by": null,
"decided_at": null,
"decision_reason": null
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /cotizaciones/{id}/discount-approval
Ask a jefe de sala or gerente to allow the discount
A draft whose discount is above the caller’s role limit cannot be sent (409 discount_approval_required on POST /cotizaciones/\{id\}/send) until a request is approved. This opens the request and tells, in the bell, every member holding cotizacion_discount:approve whose proyectos include this one. One request is open per cotización: asking again returns it (200, created: false) without telling anyone twice. Editing the draft’s discount supersedes the open request. 409 discount_within_limit when no approval is needed; 409 cotizacion_not_draft once sent. Requires leads:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
note | string | — | mín. 1, máx. 1000 |
curl -X POST https://api.vitrinadev.com/api/v1/cotizaciones/<id>/discount-approval \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"note": "Cliente cierra hoy si llegamos al 6 %."
}'Ejemplo de respuesta (200)
{
"data": {
"approval": {
"id": "0199e3a0-0000-7000-8000-000000000a01",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"status": "pending",
"requested_by": "0199e3a0-0000-7000-8000-0000000000bb",
"requested_at": "2026-10-20T12:00:00.000Z",
"note": "Cliente cierra hoy si llegamos al 6 %.",
"requested_percent": 6,
"limit_percent": 3,
"currency": "UF",
"list_total": 3510,
"discount_total": 210.6,
"total": 3299.4,
"decided_by": null,
"decided_at": null,
"decision_reason": null
},
"created": false,
"notified": 0
}
}Responde: 200 · 201 · 400 · 401 · 403 · 404 · 409 · 429
GET /cotizaciones/{id}/pdf
The cotización as a PDF
The branded PDF (the workspace’s logo and colour): lines, discounts, totals in UF and CLP, validity, and the financing block (pie, cuotas, crédito, dividendo, renta requerida). A sent cotización re-prints from its frozen figures; a draft prints marked «VISTA PREVIA». Cache-Control: private, no-store. Requires leads:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches the cotizaciones of their proyectos and leads; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/cotizaciones/<id>/pdf \
-H "Authorization: Bearer $VITRINA_KEY"Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /cotizaciones/{id}/reserva
Reserve a cotización’s unidades
From a SENT, still-valid cotización: every unidad on it becomes bloqueada until the deadline (the proyecto’s hold_hours, or hold_hours), and the buyer owes the reserva (amount + currency, else the proyecto’s reserva terms; a UF amount is charged in CLP at today’s UF). The payment is offered by the workspace’s charging preference for a reserva: a payment link (the connected provider, expiring with the hold) and/or the bank transfer, which the transfer matcher settles from the buyer’s comprobante. With deliver (default) the message goes to the buyer’s conversation as the teammate (inside the channel window; otherwise delivery.status: not_sent and the text to copy). When the reserva is fully paid the unidades become reservada, the cotización accepted and a negocio is opened (GET /negocios); the ejecutivo is notified. Unpaid at the deadline, the unidades return to disponible. 409: unit_not_available (another buyer holds one: nothing is blocked), reserva_pending, cotizacion_not_reservable, cotizacion_expired, no_contact, uf_unavailable; 400 reserva_amount_required. Requires leads:write (+ messages:send and conversations:write to deliver). Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ reservas and negocios; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
amount | number | — | > 0, ≤ 1000000000 |
currency | UF \ | CLP | — |
hold_hours | integer | — | ≥ 1, ≤ 720 |
co_buyer_contact_ids | uuid[] | — | |
conversation_id | uuid | — | |
deliver | boolean | — |
curl -X POST https://api.vitrinadev.com/api/v1/cotizaciones/<id>/reserva \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 20,
"currency": "UF"
}'Ejemplo de respuesta (201)
{
"data": {
"reserva": {
"id": "0199e3a0-0000-7000-8000-000000000a01",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"cotizacion_display_id": "CZ-12",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"co_buyer_contact_ids": [],
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"property_ids": [
"0199e3a0-0000-7000-8000-000000000401",
"0199e3a0-0000-7000-8000-000000000402"
],
"status": "pending",
"amount": 20,
"currency": "UF",
"amount_clp": 790642,
"uf_value_clp": 39532.12,
"expires_at": "2026-10-22T15:00:00.000Z",
"obligation_id": "0199e3a0-0000-7000-8000-000000000c01",
"negocio_id": null,
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T15:00:00.000Z",
"updated_at": "2026-10-20T15:00:00.000Z",
"paid_at": null,
"expired_at": null,
"cancelled_at": null,
"cancelled_reason": null,
"paid_clp": 0,
"outstanding_clp": 790642,
"payment_state": "pending",
"is_overdue": false
},
"payment": {
"mode": "mp_first",
"link": {
"checkout_id": "0199e3a0-0000-7000-8000-000000000d01",
"checkout_url": "https://api.vitrinadev.com/p/0199e3a0-0000-7000-8000-000000000d01",
"amount_clp": 790642
},
"transfer_accounts": [
{
"alias": "Cuenta corriente",
"bank": "Banco de Chile",
"account_type": "corriente",
"account_number": "00123456789",
"holder_name": "Inmobiliaria Los Aromos SpA",
"holder_rut": "76.123.456-7"
}
]
},
"text": "Hola Camila, dejamos bloqueada Departamento 1203 · 3D2B 78 m² y Estacionamiento E-12 de Parque Los Aromos para ti hasta el 22/10 a las 12:00.\nPara confirmar la reserva, paga $790.642 antes de esa hora.\n\nPaga aquí: https://api.vitrinadev.com/p/…",
"delivery": {
"status": "sent",
"reason": null,
"message_id": "0199e3a0-0000-7000-8000-000000000f01",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"channel": "whatsapp"
}
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
POST /cotizaciones/{id}/send
Send the cotización PDF by WhatsApp or email
Renders the PDF and delivers it: whatsapp on the buyer’s conversation (only inside Meta’s 24 h window: 409 whatsapp_window_closed, 409 no_whatsapp_thread) or email to the lead contact’s address (409 no_email). A draft is re-priced with today’s UF, delivered, and only then frozen as sent; a failed delivery leaves it a draft. A draft on a superseded lista de precios is a 409 price_list_superseded (re-price it first); an expired or voided one is a 409. A draft whose discount is above the sender’s role limit (max_discount_percent) is a 409 discount_approval_required until a jefe de sala or gerente approves it (POST /cotizaciones/\{id\}/discount-approval). A sent cotización can be re-sent as it was. Records who sent it and a masked recipient hint. Requires leads:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches the cotizaciones of their proyectos and leads; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
channel | whatsapp \ | email | sí |
message | string | — | mín. 1, máx. 1000 |
curl -X POST https://api.vitrinadev.com/api/v1/cotizaciones/<id>/send \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"channel": "whatsapp"
}'Ejemplo de respuesta (200)
{
"data": {
"cotizacion": {
"id": "0199e3a0-0000-7000-8000-000000000901",
"display_id": "CZ-12",
"status": "sent",
"buyer_name": "Camila Rojas",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": null,
"conversation_id": null,
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"price_list_version_id": "0199e3a0-0000-7000-8000-000000000501",
"price_list_version_number": 2,
"price_list_superseded": false,
"currency": "UF",
"uf_value_clp": 39532.12,
"uf_value_date": "2026-10-20",
"valid_until": "2026-10-27",
"discount_type": "percent",
"discount_value": 0,
"list_total": 3510,
"line_discount_total": 0,
"global_discount_total": 0,
"discount_total": 0,
"total": 3510,
"discount_percent": 0,
"notes": null,
"template_version": "cotizacion/2026-10",
"presentation": {
"ejecutivo": {
"name": "Valentina Soto",
"phone": "+56987654321",
"email": "[email protected]"
},
"sala": {
"name": "Sala Los Aromos",
"address": "Av. Vicuña Mackenna 9000, La Florida",
"hours": "Lunes a viernes 10:00–19:00 h · Sábados 10:00–14:00 h"
},
"image_url": null
},
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:05:00.000Z",
"sent_at": "2026-10-20T12:05:00.000Z",
"accepted_at": null,
"rejected_at": null,
"voided_at": null,
"voided_reason": null,
"is_expired": false,
"total_uf": 3510,
"total_clp": 138760000,
"lines": [
{
"id": "0199e3a0-0000-7000-8000-000000000902",
"position": 0,
"offering_type": "property",
"offering_id": "0199e3a0-0000-7000-8000-000000000401",
"kind": "departamento",
"label": "Departamento 1203 · 3D2B 78 m²",
"offering_number": "1203",
"detail": {
"model_name": "3D2B 78 m²",
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"floor": 12,
"orientation": "norte"
},
"quantity": 1,
"unit_price": 3310,
"discount_type": "percent",
"discount_value": 0,
"list_total": 3310,
"discount_total": 0,
"total": 3310
},
{
"id": "0199e3a0-0000-7000-8000-000000000902",
"position": 1,
"offering_type": "property",
"offering_id": "0199e3a0-0000-7000-8000-000000000402",
"kind": "estacionamiento",
"label": "Estacionamiento 45",
"offering_number": "45",
"detail": {},
"quantity": 1,
"unit_price": 200,
"discount_type": "percent",
"discount_value": 0,
"list_total": 200,
"discount_total": 0,
"total": 200
}
],
"financing": {
"pie_percent": 20,
"pie_amount": 702,
"pie_installments": 36,
"pie_installment_amount": 19.5,
"credit_amount": 2808,
"credit_years": 30,
"credit_rate_annual": 4.5,
"monthly_payment": 14.23,
"monthly_payment_clp": 562600,
"income_ratio": 0.25,
"required_income_clp": 2250400
},
"sends": [
{
"id": "0199e3a0-0000-7000-8000-000000000902",
"channel": "whatsapp",
"recipient_hint": "+56•••••4567",
"sent_by": "0199e3a0-0000-7000-8000-0000000000bb",
"sent_by_kind": "ui_member",
"sent_at": "2026-10-20T12:05:00.000Z"
}
]
},
"channel": "whatsapp",
"recipient_hint": "+56•••••4567",
"sent_at": "2026-10-20T12:05:00.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /cotizaciones/{id}/views
Who opened the cotización’s tracked link, and when
Every sent cotización carries a tracked link (it is in the message the buyer receives). Each person who opens the page or downloads its PDF through it leaves an anonymous event: a stable visitor number (1 is the first person; more than one means the link was passed on, shared: true), a device class and the time. No ip, no user agent, no identity. The ejecutivo is alerted in the bell on the first open, on a second visitor and on a return after a day. A draft has no events. Requires leads:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches the cotizaciones of their proyectos and leads; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/cotizaciones/<id>/views \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"opens": 3,
"downloads": 1,
"visitors": 2,
"shared": true,
"first_opened_at": "2026-10-20T15:02:00.000Z",
"last_opened_at": "2026-10-21T09:40:00.000Z",
"events": [
{
"id": "0199e3a0-0000-7000-8000-000000000b01",
"kind": "open",
"visitor_number": 1,
"is_first": true,
"is_new_visitor": true,
"device": "mobile",
"occurred_at": "2026-10-20T15:02:00.000Z"
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /cotizaciones/calculate
Calculate a cotización without saving it
Takes the same body as POST /cotizaciones and answers with the figures it would have (list total, discounts, total in UF and CLP, pie, dividendo, renta requerida) so a form can show them live. Saves nothing. Requires leads:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches the cotizaciones of their proyectos and leads; anything else is a 404.
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
lead_id | string | null | — | |
buyer_name | string | null | — | mín. 1, máx. 200 |
lines | object[] | sí | |
currency | UF \ | CLP | — |
valid_until | string | null | — | patrón ^\d{4}-\d{2}-\d{2}$ |
valid_days | integer | null | — | ≥ 1, ≤ 365 |
discount | object | null | — | |
financing | object | null | — | |
notes | string | null | — | máx. 2000 |
price_list_version_id | string | null | — |
curl -X POST https://api.vitrinadev.com/api/v1/cotizaciones/calculate \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"lines": [
{
"unit_id": "0199e3a0-0000-7000-8000-000000000401"
},
{
"unit_id": "0199e3a0-0000-7000-8000-000000000402"
},
{
"unit_id": "0199e3a0-0000-7000-8000-000000000403"
}
],
"currency": "UF",
"valid_days": 7,
"discount": {
"type": "percent",
"value": 2
},
"financing": {
"pie_percent": 20,
"pie_installments": 36,
"credit_years": 30,
"credit_rate_annual": 4.5
}
}'Ejemplo de respuesta (200)
{
"data": {
"id": null,
"display_id": "",
"status": "draft",
"buyer_name": "Camila Rojas",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": null,
"conversation_id": null,
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"price_list_version_id": "0199e3a0-0000-7000-8000-000000000501",
"price_list_version_number": 2,
"price_list_superseded": false,
"currency": "UF",
"uf_value_clp": 39532.12,
"uf_value_date": "2026-10-20",
"valid_until": "2026-10-27",
"discount_type": "percent",
"discount_value": 0,
"list_total": 3510,
"line_discount_total": 0,
"global_discount_total": 0,
"discount_total": 0,
"total": 3510,
"discount_percent": 0,
"notes": null,
"template_version": "cotizacion/2026-10",
"presentation": {
"ejecutivo": {
"name": "Valentina Soto",
"phone": "+56987654321",
"email": "[email protected]"
},
"sala": {
"name": "Sala Los Aromos",
"address": "Av. Vicuña Mackenna 9000, La Florida",
"hours": "Lunes a viernes 10:00–19:00 h · Sábados 10:00–14:00 h"
},
"image_url": null
},
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:05:00.000Z",
"sent_at": null,
"accepted_at": null,
"rejected_at": null,
"voided_at": null,
"voided_reason": null,
"is_expired": false,
"total_uf": 3510,
"total_clp": 138760000,
"lines": [
{
"id": "0199e3a0-0000-7000-8000-000000000902",
"position": 0,
"offering_type": "property",
"offering_id": "0199e3a0-0000-7000-8000-000000000401",
"kind": "departamento",
"label": "Departamento 1203 · 3D2B 78 m²",
"offering_number": "1203",
"detail": {
"model_name": "3D2B 78 m²",
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"floor": 12,
"orientation": "norte"
},
"quantity": 1,
"unit_price": 3310,
"discount_type": "percent",
"discount_value": 0,
"list_total": 3310,
"discount_total": 0,
"total": 3310
},
{
"id": "0199e3a0-0000-7000-8000-000000000902",
"position": 1,
"offering_type": "property",
"offering_id": "0199e3a0-0000-7000-8000-000000000402",
"kind": "estacionamiento",
"label": "Estacionamiento 45",
"offering_number": "45",
"detail": {},
"quantity": 1,
"unit_price": 200,
"discount_type": "percent",
"discount_value": 0,
"list_total": 200,
"discount_total": 0,
"total": 200
}
],
"financing": {
"pie_percent": 20,
"pie_amount": 702,
"pie_installments": 36,
"pie_installment_amount": 19.5,
"credit_amount": 2808,
"credit_years": 30,
"credit_rate_annual": 4.5,
"monthly_payment": 14.23,
"monthly_payment_clp": 562600,
"income_ratio": 0.25,
"required_income_clp": 2250400
},
"sends": []
},
"meta": {
"uf_value": {
"clp": 39532.12,
"date": "2026-10-20"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /datahunter-import
Datahunter import steps 2–3: dry run, then load the history
Loads Datahunter's history as records (decision D18): proyectos (matched by name), unidades with their tipologías (the stock import's rules: proyecto + kind + number, protected fields kept), leads, propietarios, cotizaciones and negocios. Send the files as multipart parts (proyectos, unidades, leads, propietarios, cotizaciones, negocios; any subset) with mapping as JSON text, or JSON rows per file (the MCP and extractor path). dry_run defaults to true: all the files are planned together and the report says what would be created, updated, left unchanged, skipped (repeats) or rejected, row by row for the problems, and balances against the source row counts (totals.balanced). People (leads, owners, buyers) are matched to existing contacts by RUT, then phone, then email, and the same person on several rows is one contact; a matched contact is never rewritten. Imported leads are history: contacts are import-only (no conversation, no automation reaches them), leads keep their original dates and carry source import, and nothing is sent. Lead etapas map to the pipeline’s stages through stage_mapping (the dry run lists them in lead_stages). Cotizaciones and negocios are staged (counted in staged) until the cotización and negocio tables exist; their contact, proyecto and unidad are already resolved. A negocio or owner raises its unidad’s status (reservada, promesada, vendida) and never lowers it. Send dry_run: false with step to run one file at a time (the screen’s progress), in the order proyectos, unidades, leads, propietarios, cotizaciones, negocios; each step is its own batch and re-running a step changes nothing. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Needs a caller who sees every proyecto (a narrowed ejecutivo answers 403).
curl -X POST https://api.vitrinadev.com/api/v1/datahunter-import \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"rows": {
"leads": [
{
"name": "Ana Soto",
"rut": "12.345.678-5",
"phone": "+56987654321",
"project": "Parque Aromos",
"stage": "Cotizó",
"created_at": "03/05/2024"
}
]
},
"dry_run": true
}'Ejemplo de respuesta (200)
{
"data": {
"dry_run": true,
"step": null,
"batch_ids": [],
"mapping": {
"leads": {
"name": "Nombre",
"project": "Proyecto"
}
},
"ignored_status_columns": [],
"pipeline": {
"id": "0199e3a0-0000-7000-8000-000000000501",
"name": "Ventas"
},
"entities": {
"leads": {
"summary": {
"source_rows": 1840,
"create": 1790,
"update": 0,
"unchanged": 0,
"skipped": 12,
"error": 38,
"balanced": true
},
"issues": [],
"issues_truncated": false,
"sample": []
}
},
"totals": {
"source_rows": 1840,
"create": 1790,
"update": 0,
"unchanged": 0,
"skipped": 12,
"error": 38,
"balanced": true
},
"contacts": {
"people": 1604,
"create": 1590,
"match_existing": 14,
"merged_in_file": 186
},
"unit_models_to_create": 0,
"unit_status_changes": {
"reservada": 0,
"promesada": 0,
"vendida": 0,
"unchanged": 0
},
"lead_stages": [],
"negocios_by_stage": {
"reserva": 0,
"promesa": 0,
"escritura": 0,
"entrega": 0,
"desistido": 0
},
"staged": {
"cotizacion": 0,
"negocio": 0
},
"written": null
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /datahunter-import/batches
Datahunter import: past batches and what is staged
The committed steps, newest first, each with its reconciliation counts, plus how many carried-over records wait in each state (staged cotizaciones and negocios wait for their tables). Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Needs a caller who sees every proyecto (a narrowed ejecutivo answers 403).
curl https://api.vitrinadev.com/api/v1/datahunter-import/batches \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"batches": [],
"staged": [
{
"entity": "negocio",
"state": "staged",
"n": 212
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /datahunter-import/columns
Datahunter import step 1: read the files’ columns
Multipart, one part per file, named proyectos, unidades, leads, propietarios, cotizaciones or negocios (.xlsx, .xls or .csv, up to 20 MB each, any subset). For each file returns its header, the first rows, the mapping we suggest from the column names and every field a column can feed — the mapping screen. A file whose columns are named by the field keys (what the #4806 extractor writes) maps with no input. Writes and stores nothing. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Needs a caller who sees every proyecto (a narrowed ejecutivo answers 403).
curl -X POST https://api.vitrinadev.com/api/v1/datahunter-import/columns \
-H "Authorization: Bearer $VITRINA_KEY" \
-F "leads=(binary: leads-datahunter.xlsx)"Ejemplo de respuesta (200)
{
"data": {
"files": [
{
"entity": "leads",
"format": "xlsx",
"sheet_name": "Leads",
"header": [
"Nombre",
"RUT",
"Celular",
"Proyecto",
"Etapa",
"Fecha"
],
"row_count": 1840,
"sample": [
[
"Ana Soto",
"12.345.678-5",
"+56 9 8765 4321",
"Parque Aromos",
"Cotizó",
"03/05/2024"
]
],
"suggested_mapping": {
"name": "Nombre",
"rut": "RUT",
"phone": "Celular",
"project": "Proyecto",
"stage": "Etapa",
"created_at": "Fecha"
},
"ignored_status_columns": [],
"fields": [
{
"key": "name",
"label": "Nombre",
"required": true,
"description": "The person’s full name."
}
]
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /floor-plans/{id}
Remove a floor plan
Removes the plan and its placements. The unidades themselves are untouched. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/floor-plans/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000501",
"deleted": true
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /floor-plans/{id}
Get a floor plan
One plan with the live unidades placed on it. Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/floor-plans/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000501",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Piso 12",
"floor": 12,
"image_url": "https://media.example.com/t/other/aromos-piso-12.png",
"image_width": 1600,
"image_height": 1000,
"sort_order": 12,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"units": [
{
"unit_id": "0199e3a0-0000-7000-8000-000000000401",
"shape": [
[
0.1,
0.2
],
[
0.3,
0.2
],
[
0.3,
0.45
],
[
0.1,
0.45
]
]
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /floor-plans/{id}
Edit a floor plan
Rename it, change its floor, order or image. Changing the image keeps the placements: their coordinates are fractions of the image, so a re-export of the same plan at another size still fits. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X PATCH https://api.vitrinadev.com/api/v1/floor-plans/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Piso 12 (torre A)"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000501",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Piso 12",
"floor": 12,
"image_url": "https://media.example.com/t/other/aromos-piso-12.png",
"image_width": 1600,
"image_height": 1000,
"sort_order": 12,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"units": [
{
"unit_id": "0199e3a0-0000-7000-8000-000000000401",
"shape": [
[
0.1,
0.2
],
[
0.3,
0.2
],
[
0.3,
0.45
],
[
0.1,
0.45
]
]
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /floor-plans/{id}/units
Place unidades on a floor plan
Replaces every placement of the plan with units: each a unidad of the plan’s own proyecto, once, with a polygon of 3 to 64 [x, y] points as fractions (0..1) of the image, origin top-left. A unidad of another proyecto, a removed one or a repeated one is a 400 naming the ids, and nothing is written. An empty list clears the plan. A unidad may sit on several plans (a dúplex). Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X PUT https://api.vitrinadev.com/api/v1/floor-plans/<id>/units \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"units": [
{
"unit_id": "0199e3a0-0000-7000-8000-000000000401",
"shape": [
[
0.1,
0.2
],
[
0.3,
0.2
],
[
0.3,
0.45
],
[
0.1,
0.45
]
]
}
]
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000501",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Piso 12",
"floor": 12,
"image_url": "https://media.example.com/t/other/aromos-piso-12.png",
"image_width": 1600,
"image_height": 1000,
"sort_order": 12,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"units": [
{
"unit_id": "0199e3a0-0000-7000-8000-000000000401",
"shape": [
[
0.1,
0.2
],
[
0.3,
0.2
],
[
0.3,
0.45
],
[
0.1,
0.45
]
]
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /handovers
List actas de entrega
Newest first, with the proyecto, the unidad, the owner and how many lines are observed / still unreviewed. Filters: project_id, property_id, status. Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
project_id | query | uuid | no | |
property_id | query | uuid | no | |
status | query | draft \ | pending_signature \ | signed \ |
limit | query | integer | no | ≥ 1, ≤ 200 |
offset | query | integer | null | no | ≥ 0 |
curl https://api.vitrinadev.com/api/v1/handovers \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000b21",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"property_id": "0199e3a0-0000-7000-8000-000000000401",
"contact_id": "0199e3a0-0000-7000-8000-000000000c01",
"status": "draft",
"notes": null,
"performed_by": null,
"performed_at": "2026-10-20T12:00:00.000Z",
"signer_name": null,
"signed_at": null,
"signature_method": null,
"signed_pdf_sha256": null,
"signed_pdf_bytes": null,
"sent_for_signature_at": null,
"attested_at": null,
"cancelled_at": null,
"created_at": "2026-10-20T12:00:00.000Z",
"project_name": "Vista Golf Departamentos",
"unit_label": "departamento 302",
"contact_name": "Marcela Ortiz",
"items_total": 30,
"items_observations": 1,
"items_pending": 3
}
],
"meta": {
"pagination": {
"total": 1,
"limit": 50,
"offset": 0
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /handovers
Open the acta de entrega of a unidad
One live acta per unidad (409 handover_id of the existing one). The checklist is born with it: the proyecto’s own list (/projects/\{id\}/entrega-checklist) or the platform default, in walking order. The owner is the unidad’s registered owner or the contact_id given (and becomes the registered owner). Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
curl -X POST https://api.vitrinadev.com/api/v1/handovers \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"property_id": "0199e3a0-0000-7000-8000-000000000401",
"contact_id": "0199e3a0-0000-7000-8000-000000000c01"
}'Ejemplo de respuesta (201)
{
"data": {
"handover": {
"id": "0199e3a0-0000-7000-8000-000000000b21",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"property_id": "0199e3a0-0000-7000-8000-000000000401",
"contact_id": "0199e3a0-0000-7000-8000-000000000c01",
"status": "draft",
"notes": null,
"performed_by": null,
"performed_at": "2026-10-20T12:00:00.000Z",
"signer_name": null,
"signed_at": null,
"signature_method": null,
"signed_pdf_sha256": null,
"signed_pdf_bytes": null,
"sent_for_signature_at": null,
"attested_at": null,
"cancelled_at": null,
"created_at": "2026-10-20T12:00:00.000Z"
},
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Vista Golf Departamentos"
},
"unit": {
"id": "0199e3a0-0000-7000-8000-000000000401",
"label": "departamento 302",
"address": "Av. Vicuña Mackenna 0000",
"comuna": "La Florida"
},
"owner": {
"id": "0199e3a0-0000-7000-8000-000000000c01",
"name": "Marcela Ortiz"
},
"sections": [
{
"title": "Baños",
"items": [
{
"id": "0199e3a0-0000-7000-8000-000000000b31",
"handover_id": "0199e3a0-0000-7000-8000-000000000b21",
"section": "Baños",
"item_key": "bano_griferia",
"label": "Grifería, presión de agua y desagües",
"position": 12,
"state": "observation",
"partida": "instalaciones_sanitarias",
"priority": "normal",
"note": "El lavamanos gotea por la base.",
"split_case": false
}
]
}
],
"media": [],
"casos": [],
"counts": {
"total": 30,
"ok": 24,
"observation": 1,
"na": 2,
"pending": 3
}
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /handovers/{id}
Cancel an acta that is not signed
A signed acta is never cancelled (409). A cancelled one frees the unidad for a new acta. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/handovers/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Responde: 204 · 400 · 401 · 403 · 404 · 409 · 429
GET /handovers/{id}
One acta: checklist by section, photos and casos
Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/handovers/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"handover": {
"id": "0199e3a0-0000-7000-8000-000000000b21",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"property_id": "0199e3a0-0000-7000-8000-000000000401",
"contact_id": "0199e3a0-0000-7000-8000-000000000c01",
"status": "draft",
"notes": null,
"performed_by": null,
"performed_at": "2026-10-20T12:00:00.000Z",
"signer_name": null,
"signed_at": null,
"signature_method": null,
"signed_pdf_sha256": null,
"signed_pdf_bytes": null,
"sent_for_signature_at": null,
"attested_at": null,
"cancelled_at": null,
"created_at": "2026-10-20T12:00:00.000Z"
},
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Vista Golf Departamentos"
},
"unit": {
"id": "0199e3a0-0000-7000-8000-000000000401",
"label": "departamento 302",
"address": "Av. Vicuña Mackenna 0000",
"comuna": "La Florida"
},
"owner": {
"id": "0199e3a0-0000-7000-8000-000000000c01",
"name": "Marcela Ortiz"
},
"sections": [
{
"title": "Baños",
"items": [
{
"id": "0199e3a0-0000-7000-8000-000000000b31",
"handover_id": "0199e3a0-0000-7000-8000-000000000b21",
"section": "Baños",
"item_key": "bano_griferia",
"label": "Grifería, presión de agua y desagües",
"position": 12,
"state": "observation",
"partida": "instalaciones_sanitarias",
"priority": "normal",
"note": "El lavamanos gotea por la base.",
"split_case": false
}
]
}
],
"media": [],
"casos": [],
"counts": {
"total": 30,
"ok": 24,
"observation": 1,
"na": 2,
"pending": 3
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /handovers/{id}
Write the acta’s general notes
Drafts only (409 otherwise). Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X PATCH https://api.vitrinadev.com/api/v1/handovers/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"notes": "Se entregan 2 juegos de llaves."
}'Ejemplo de respuesta (200)
{
"data": {
"handover": {
"id": "0199e3a0-0000-7000-8000-000000000b21",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"property_id": "0199e3a0-0000-7000-8000-000000000401",
"contact_id": "0199e3a0-0000-7000-8000-000000000c01",
"status": "draft",
"notes": null,
"performed_by": null,
"performed_at": "2026-10-20T12:00:00.000Z",
"signer_name": null,
"signed_at": null,
"signature_method": null,
"signed_pdf_sha256": null,
"signed_pdf_bytes": null,
"sent_for_signature_at": null,
"attested_at": null,
"cancelled_at": null,
"created_at": "2026-10-20T12:00:00.000Z"
},
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Vista Golf Departamentos"
},
"unit": {
"id": "0199e3a0-0000-7000-8000-000000000401",
"label": "departamento 302",
"address": "Av. Vicuña Mackenna 0000",
"comuna": "La Florida"
},
"owner": {
"id": "0199e3a0-0000-7000-8000-000000000c01",
"name": "Marcela Ortiz"
},
"sections": [
{
"title": "Baños",
"items": [
{
"id": "0199e3a0-0000-7000-8000-000000000b31",
"handover_id": "0199e3a0-0000-7000-8000-000000000b21",
"section": "Baños",
"item_key": "bano_griferia",
"label": "Grifería, presión de agua y desagües",
"position": 12,
"state": "observation",
"partida": "instalaciones_sanitarias",
"priority": "normal",
"note": "El lavamanos gotea por la base.",
"split_case": false
}
]
}
],
"media": [],
"casos": [],
"counts": {
"total": 30,
"ok": 24,
"observation": 1,
"na": 2,
"pending": 3
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /handovers/{id}/attest
Confirm the owner’s identity in person
For the entrega with the owner in front of staff (cédula in hand): the owner signs without a WhatsApp code for the next 12 hours, and the signature is recorded as in_person with who attested. Requires the acta to be sent (pending_signature). Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/handovers/<id>/attest \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"handover": {
"id": "0199e3a0-0000-7000-8000-000000000b21",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"property_id": "0199e3a0-0000-7000-8000-000000000401",
"contact_id": "0199e3a0-0000-7000-8000-000000000c01",
"status": "draft",
"notes": null,
"performed_by": null,
"performed_at": "2026-10-20T12:00:00.000Z",
"signer_name": null,
"signed_at": null,
"signature_method": null,
"signed_pdf_sha256": null,
"signed_pdf_bytes": null,
"sent_for_signature_at": null,
"attested_at": null,
"cancelled_at": null,
"created_at": "2026-10-20T12:00:00.000Z"
},
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Vista Golf Departamentos"
},
"unit": {
"id": "0199e3a0-0000-7000-8000-000000000401",
"label": "departamento 302",
"address": "Av. Vicuña Mackenna 0000",
"comuna": "La Florida"
},
"owner": {
"id": "0199e3a0-0000-7000-8000-000000000c01",
"name": "Marcela Ortiz"
},
"sections": [
{
"title": "Baños",
"items": [
{
"id": "0199e3a0-0000-7000-8000-000000000b31",
"handover_id": "0199e3a0-0000-7000-8000-000000000b21",
"section": "Baños",
"item_key": "bano_griferia",
"label": "Grifería, presión de agua y desagües",
"position": 12,
"state": "observation",
"partida": "instalaciones_sanitarias",
"priority": "normal",
"note": "El lavamanos gotea por la base.",
"split_case": false
}
]
}
],
"media": [],
"casos": [],
"counts": {
"total": 30,
"ok": 24,
"observation": 1,
"na": 2,
"pending": 3
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /handovers/{id}/casos
Open the post-venta casos of a signed acta
Signing opens them already; this is the retry when that step failed. Idempotent: a line that already has its observación is skipped. The lines together open ONE caso with several observaciones; a line marked split_case opens its own. Each caso carries the unidad, the proyecto, the highest priority of its lines and the photos. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/handovers/<id>/casos \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (201)
{
"data": {
"casos": [
{
"id": "0199e3a0-0000-7000-8000-000000000a01",
"display_id": "T-12",
"observations": 3
}
]
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /handovers/{id}/items/{itemId}
Answer a checklist line
state: ok (conforme), observation (a defect), na or pending. An observation needs its partida (preselected from the line) and a note; priority and split_case only mean something on an observation (leaving the state resets them). Drafts only. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
itemId | path | uuid | sí |
curl -X PATCH https://api.vitrinadev.com/api/v1/handovers/<id>/items/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"state": "observation",
"partida": "instalaciones_sanitarias",
"note": "El lavamanos gotea por la base."
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000b31",
"handover_id": "0199e3a0-0000-7000-8000-000000000b21",
"section": "Baños",
"item_key": "bano_griferia",
"label": "Grifería, presión de agua y desagües",
"position": 12,
"state": "observation",
"partida": "instalaciones_sanitarias",
"priority": "normal",
"note": "El lavamanos gotea por la base.",
"split_case": false
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /handovers/{id}/media
Attach photos or videos to the walk
Upload the file with POST /tenant/media first and send its url, optionally on one line (item_id). A url already on the acta is left as it is. The photos of an observation travel to its caso when the acta is signed. Drafts only. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/handovers/<id>/media \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"item_id": "0199e3a0-0000-7000-8000-000000000b31",
"url": "https://media.example.com/t/other/lavamanos.jpg",
"caption": "Gotea por la base"
}
]
}'Ejemplo de respuesta (201)
{
"data": {
"handover": {
"id": "0199e3a0-0000-7000-8000-000000000b21",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"property_id": "0199e3a0-0000-7000-8000-000000000401",
"contact_id": "0199e3a0-0000-7000-8000-000000000c01",
"status": "draft",
"notes": null,
"performed_by": null,
"performed_at": "2026-10-20T12:00:00.000Z",
"signer_name": null,
"signed_at": null,
"signature_method": null,
"signed_pdf_sha256": null,
"signed_pdf_bytes": null,
"sent_for_signature_at": null,
"attested_at": null,
"cancelled_at": null,
"created_at": "2026-10-20T12:00:00.000Z"
},
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Vista Golf Departamentos"
},
"unit": {
"id": "0199e3a0-0000-7000-8000-000000000401",
"label": "departamento 302",
"address": "Av. Vicuña Mackenna 0000",
"comuna": "La Florida"
},
"owner": {
"id": "0199e3a0-0000-7000-8000-000000000c01",
"name": "Marcela Ortiz"
},
"sections": [
{
"title": "Baños",
"items": [
{
"id": "0199e3a0-0000-7000-8000-000000000b31",
"handover_id": "0199e3a0-0000-7000-8000-000000000b21",
"section": "Baños",
"item_key": "bano_griferia",
"label": "Grifería, presión de agua y desagües",
"position": 12,
"state": "observation",
"partida": "instalaciones_sanitarias",
"priority": "normal",
"note": "El lavamanos gotea por la base.",
"split_case": false
}
]
}
],
"media": [],
"casos": [],
"counts": {
"total": 30,
"ok": 24,
"observation": 1,
"na": 2,
"pending": 3
}
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
GET /handovers/{id}/pdf
Download the signed acta
The sealed PDF, its SHA-256 re-verified on every read: an object that no longer matches what was signed is refused (409). 404 until the acta is signed. Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/handovers/<id>/pdf \
-H "Authorization: Bearer $VITRINA_KEY"Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /handovers/{id}/reopen
Reopen an acta that was sent, to correct it
Back to draft; the owner’s link stops showing it until it is sent again. Only before it is signed. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/handovers/<id>/reopen \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"handover": {
"id": "0199e3a0-0000-7000-8000-000000000b21",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"property_id": "0199e3a0-0000-7000-8000-000000000401",
"contact_id": "0199e3a0-0000-7000-8000-000000000c01",
"status": "draft",
"notes": null,
"performed_by": null,
"performed_at": "2026-10-20T12:00:00.000Z",
"signer_name": null,
"signed_at": null,
"signature_method": null,
"signed_pdf_sha256": null,
"signed_pdf_bytes": null,
"sent_for_signature_at": null,
"attested_at": null,
"cancelled_at": null,
"created_at": "2026-10-20T12:00:00.000Z"
},
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Vista Golf Departamentos"
},
"unit": {
"id": "0199e3a0-0000-7000-8000-000000000401",
"label": "departamento 302",
"address": "Av. Vicuña Mackenna 0000",
"comuna": "La Florida"
},
"owner": {
"id": "0199e3a0-0000-7000-8000-000000000c01",
"name": "Marcela Ortiz"
},
"sections": [
{
"title": "Baños",
"items": [
{
"id": "0199e3a0-0000-7000-8000-000000000b31",
"handover_id": "0199e3a0-0000-7000-8000-000000000b21",
"section": "Baños",
"item_key": "bano_griferia",
"label": "Grifería, presión de agua y desagües",
"position": 12,
"state": "observation",
"partida": "instalaciones_sanitarias",
"priority": "normal",
"note": "El lavamanos gotea por la base.",
"split_case": false
}
]
}
],
"media": [],
"casos": [],
"counts": {
"total": 30,
"ok": 24,
"observation": 1,
"na": 2,
"pending": 3
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /handovers/{id}/send
Send the acta to the owner to sign
Every line must be answered (400 otherwise, naming how many are pending). The acta is frozen and the owner gets a no-login link (/acta/<token>, 14 days) by WhatsApp text; notified says whether it went out (a closed 24 h window or a missing number comes back in notify_error). With notify: false only the link returns, to show on the staff device at the entrega. Calling it again on a pending acta mints a fresh link. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/handovers/<id>/send \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"notify": true
}'Ejemplo de respuesta (200)
{
"data": {
"link": "https://app.example.com/acta/eyJhbGciOi…",
"notified": true,
"notify_error": null
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /negocios
List negocios
An inmobiliaria’s sales from reserva to entrega, newest reserva first. Filters: project_id, stage, lead_id, contact_id. Requires leads:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ reservas and negocios; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
project_id | query | uuid[] | no | |
stage | query | reservado \ | promesado \ | escriturado \ |
lead_id | query | uuid | no | |
contact_id | query | uuid | no | |
limit | query | integer | no | ≥ 1, ≤ 200 |
offset | query | integer | null | no | ≥ 0 |
curl https://api.vitrinadev.com/api/v1/negocios \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000b01",
"display_id": "NG-3",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"reserva_id": "0199e3a0-0000-7000-8000-000000000a01",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"buyer_name": "Camila Rojas",
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"stage": "reservado",
"currency": "UF",
"total": 3510,
"uf_value_clp": 39532.12,
"reserved_at": "2026-10-21T13:10:00.000Z",
"created_at": "2026-10-21T13:10:00.000Z",
"updated_at": "2026-10-21T13:10:00.000Z",
"promesa_due_on": "2026-11-20",
"promesa_signed_on": null,
"escritura_due_on": null,
"escritura_signed_on": null,
"escritura_notary": null,
"entrega_due_on": null,
"entregado_on": null,
"desisted_on": null,
"desist_reason": null,
"desist_money_outcome": null,
"desist_notes": null,
"milestone_alerted_key": null,
"next_deadline": {
"milestone": "promesa",
"due_on": "2026-11-20",
"overdue": false
}
}
],
"meta": {
"pagination": {
"total": 1,
"limit": 50,
"offset": 0
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /negocios/{id}
Get a negocio
One negocio: the buyer(s), the unidades at the accepted cotización’s prices (with their current status), the stage and the reserva that opened it. Requires leads:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ reservas and negocios; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/negocios/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000b01",
"display_id": "NG-3",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"reserva_id": "0199e3a0-0000-7000-8000-000000000a01",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"buyer_name": "Camila Rojas",
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"stage": "reservado",
"currency": "UF",
"total": 3510,
"uf_value_clp": 39532.12,
"reserved_at": "2026-10-21T13:10:00.000Z",
"created_at": "2026-10-21T13:10:00.000Z",
"updated_at": "2026-10-21T13:10:00.000Z",
"promesa_due_on": "2026-11-20",
"promesa_signed_on": null,
"escritura_due_on": null,
"escritura_signed_on": null,
"escritura_notary": null,
"entrega_due_on": null,
"entregado_on": null,
"desisted_on": null,
"desist_reason": null,
"desist_money_outcome": null,
"desist_notes": null,
"milestone_alerted_key": null,
"next_deadline": {
"milestone": "promesa",
"due_on": "2026-11-20",
"overdue": false
},
"buyers": [
{
"id": "0199e3a0-0000-7000-8000-000000000b11",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"contact_name": "Camila Rojas",
"role": "titular",
"position": 0
}
],
"units": [
{
"id": "0199e3a0-0000-7000-8000-000000000b21",
"property_id": "0199e3a0-0000-7000-8000-000000000401",
"property_display_id": "I-41",
"kind": "departamento",
"label": "Departamento 1203 · 3D2B 78 m²",
"unit_number": "1203",
"price": 3310,
"position": 0,
"released_at": null,
"status": "reservada"
},
{
"id": "0199e3a0-0000-7000-8000-000000000b22",
"property_id": "0199e3a0-0000-7000-8000-000000000402",
"property_display_id": "I-87",
"kind": "estacionamiento",
"label": "Estacionamiento E-12",
"unit_number": "E-12",
"price": 200,
"position": 1,
"released_at": null,
"status": "reservada"
}
],
"reserva": {
"id": "0199e3a0-0000-7000-8000-000000000a01",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"cotizacion_display_id": "CZ-12",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"co_buyer_contact_ids": [],
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"property_ids": [
"0199e3a0-0000-7000-8000-000000000401",
"0199e3a0-0000-7000-8000-000000000402"
],
"status": "paid",
"amount": 20,
"currency": "UF",
"amount_clp": 790642,
"uf_value_clp": 39532.12,
"expires_at": "2026-10-22T15:00:00.000Z",
"obligation_id": "0199e3a0-0000-7000-8000-000000000c01",
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T15:00:00.000Z",
"updated_at": "2026-10-20T15:00:00.000Z",
"paid_at": "2026-10-21T13:10:00.000Z",
"expired_at": null,
"cancelled_at": null,
"cancelled_reason": null
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /negocios/{id}/bank-approvals
A negocio’s bank approvals
One row per bank: en_evaluacion → pre_aprobado → aprobado | rechazado, with amount, rate, term and dates, side by side. Requires leads:read. Only on a workspace that runs the Proyectos module; any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/negocios/<id>/bank-approvals \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000f21",
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"bank": "Banco Estado",
"status": "pre_aprobado",
"amount": 2800,
"currency": "UF",
"rate_annual": 4.39,
"term_years": 30,
"decided_on": "2026-10-28",
"expires_on": "2027-01-28",
"notes": null,
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_at": "2026-10-25T12:00:00.000Z",
"updated_at": "2026-10-28T12:00:00.000Z"
},
{
"id": "0199e3a0-0000-7000-8000-000000000f22",
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"bank": "Banco de Chile",
"status": "en_evaluacion",
"amount": null,
"currency": null,
"rate_annual": null,
"term_years": null,
"decided_on": null,
"expires_on": null,
"notes": null,
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_at": "2026-10-25T12:00:00.000Z",
"updated_at": "2026-10-28T12:00:00.000Z"
}
]
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /negocios/{id}/bank-approvals
Track a bank’s approval
One row per bank and negocio (409 bank_already_tracked). amount and currency go together. Requires leads:write. Only on a workspace that runs the Proyectos module; any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
bank | string | sí | mín. 1, máx. 200 |
status | en_evaluacion \ | pre_aprobado \ | aprobado \ |
amount | number | null | — | > 0, ≤ 1000000000 |
currency | UF \ | CLP | — |
rate_annual | number | null | — | ≥ 0, ≤ 30 |
term_years | integer | null | — | ≥ 1, ≤ 40 |
decided_on | string | null | — | patrón ^\d{4}-\d{2}-\d{2}$ |
expires_on | string | null | — | patrón ^\d{4}-\d{2}-\d{2}$ |
notes | string | null | — | máx. 2000 |
curl -X POST https://api.vitrinadev.com/api/v1/negocios/<id>/bank-approvals \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"bank": "Banco Estado",
"status": "en_evaluacion"
}'Ejemplo de respuesta (201)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000f21",
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"bank": "Banco Estado",
"status": "pre_aprobado",
"amount": 2800,
"currency": "UF",
"rate_annual": 4.39,
"term_years": 30,
"decided_on": "2026-10-28",
"expires_on": "2027-01-28",
"notes": null,
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_at": "2026-10-25T12:00:00.000Z",
"updated_at": "2026-10-28T12:00:00.000Z"
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /negocios/{id}/bank-approvals/{approvalId}
Stop tracking a bank
Requires leads:write. Only on a workspace that runs the Proyectos module; any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
approvalId | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/negocios/<id>/bank-approvals/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000f21",
"deleted": true
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /negocios/{id}/bank-approvals/{approvalId}
Update a bank’s approval
Any field; the status moves freely as the bank answers. Requires leads:write. Only on a workspace that runs the Proyectos module; any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
approvalId | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
bank | string | — | mín. 1, máx. 200 |
status | en_evaluacion \ | pre_aprobado \ | aprobado \ |
amount | number | null | — | > 0, ≤ 1000000000 |
currency | UF \ | CLP | — |
rate_annual | number | null | — | ≥ 0, ≤ 30 |
term_years | integer | null | — | ≥ 1, ≤ 40 |
decided_on | string | null | — | patrón ^\d{4}-\d{2}-\d{2}$ |
expires_on | string | null | — | patrón ^\d{4}-\d{2}-\d{2}$ |
notes | string | null | — | máx. 2000 |
curl -X PATCH https://api.vitrinadev.com/api/v1/negocios/<id>/bank-approvals/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": "aprobado",
"amount": 2800,
"currency": "UF",
"rate_annual": 4.29,
"term_years": 30,
"decided_on": "2026-11-05"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000f21",
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"bank": "Banco Estado",
"status": "aprobado",
"amount": 2800,
"currency": "UF",
"rate_annual": 4.39,
"term_years": 30,
"decided_on": "2026-10-28",
"expires_on": "2027-01-28",
"notes": null,
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_at": "2026-10-25T12:00:00.000Z",
"updated_at": "2026-10-28T12:00:00.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /negocios/{id}/buyer-view
What the buyer can be told on WhatsApp
The negocio exactly as the WhatsApp agent reads it for its buyer (my_property): stage, next deadline, entrega date, pending documents, the pie, the proyecto’s latest obra posts and, for unidades with a registered owner, the status of their post-venta casos. The agent reveals it only to the WhatsApp number of the negocio’s titular or cotitular (post-venta: of the unidad’s owner). Requires leads:read. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/negocios/<id>/buyer-view \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"identity": [
"Camila Rojas"
],
"negocios": [
{
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"display_id": "NG-3",
"project_name": "Parque Los Aromos",
"stage": "promesado",
"stage_label": "Promesa firmada",
"units": [
"Departamento 604"
],
"next_deadline": {
"milestone": "escritura",
"label": "firma de la escritura",
"due_on": "2026-12-15",
"overdue": false
},
"entrega": {
"due_on": "2027-03-30",
"delivered_on": null
},
"documents": {
"pending": [],
"total_required": 4
},
"pie": null
}
],
"obra": [],
"postventa": []
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /negocios/{id}/cuotas/{number}/payment
How a cuota can be paid
The cuota’s payment link (the connected provider) and/or transfer accounts, by the workspace’s charging preference. 409 cuota_not_open. Requires leads:read. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
number | path | integer | sí | ≥ 1, ≤ 36 |
curl https://api.vitrinadev.com/api/v1/negocios/<id>/cuotas/<id>/payment \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"number": 1,
"due_on": "2026-11-20",
"amount_clp": 2312629,
"mode": "mp_first",
"link": {
"checkout_id": "0199e3a0-0000-7000-8000-000000000d02",
"checkout_url": "https://api.vitrinadev.com/p/…",
"amount_clp": 2312629
},
"transfer_accounts": []
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /negocios/{id}/deadlines
Edit a negocio’s deadlines
Moves the promesa, escritura or entrega deadline (null clears it) and the escritura’s notaría. A moved deadline alerts again if it passes. 409 negocio_closed for a desistido or entregado negocio. Requires leads:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ reservas and negocios; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
promesa_due_on | string | null | — | patrón ^\d{4}-\d{2}-\d{2}$ |
escritura_due_on | string | null | — | patrón ^\d{4}-\d{2}-\d{2}$ |
entrega_due_on | string | null | — | patrón ^\d{4}-\d{2}-\d{2}$ |
escritura_notary | string | null | — | mín. 1, máx. 200 |
curl -X PATCH https://api.vitrinadev.com/api/v1/negocios/<id>/deadlines \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"promesa_due_on": "2026-11-30"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000b01",
"display_id": "NG-3",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"reserva_id": "0199e3a0-0000-7000-8000-000000000a01",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"buyer_name": "Camila Rojas",
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"stage": "reservado",
"currency": "UF",
"total": 3510,
"uf_value_clp": 39532.12,
"reserved_at": "2026-10-21T13:10:00.000Z",
"created_at": "2026-10-21T13:10:00.000Z",
"updated_at": "2026-10-21T13:10:00.000Z",
"promesa_due_on": "2026-11-20",
"promesa_signed_on": null,
"escritura_due_on": null,
"escritura_signed_on": null,
"escritura_notary": null,
"entrega_due_on": null,
"entregado_on": null,
"desisted_on": null,
"desist_reason": null,
"desist_money_outcome": null,
"desist_notes": null,
"milestone_alerted_key": null,
"next_deadline": {
"milestone": "promesa",
"due_on": "2026-11-20",
"overdue": false
},
"buyers": [
{
"id": "0199e3a0-0000-7000-8000-000000000b11",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"contact_name": "Camila Rojas",
"role": "titular",
"position": 0
}
],
"units": [
{
"id": "0199e3a0-0000-7000-8000-000000000b21",
"property_id": "0199e3a0-0000-7000-8000-000000000401",
"property_display_id": "I-41",
"kind": "departamento",
"label": "Departamento 1203 · 3D2B 78 m²",
"unit_number": "1203",
"price": 3310,
"position": 0,
"released_at": null,
"status": "reservada"
},
{
"id": "0199e3a0-0000-7000-8000-000000000b22",
"property_id": "0199e3a0-0000-7000-8000-000000000402",
"property_display_id": "I-87",
"kind": "estacionamiento",
"label": "Estacionamiento E-12",
"unit_number": "E-12",
"price": 200,
"position": 1,
"released_at": null,
"status": "reservada"
}
],
"reserva": {
"id": "0199e3a0-0000-7000-8000-000000000a01",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"cotizacion_display_id": "CZ-12",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"co_buyer_contact_ids": [],
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"property_ids": [
"0199e3a0-0000-7000-8000-000000000401",
"0199e3a0-0000-7000-8000-000000000402"
],
"status": "paid",
"amount": 20,
"currency": "UF",
"amount_clp": 790642,
"uf_value_clp": 39532.12,
"expires_at": "2026-10-22T15:00:00.000Z",
"obligation_id": "0199e3a0-0000-7000-8000-000000000c01",
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T15:00:00.000Z",
"updated_at": "2026-10-20T15:00:00.000Z",
"paid_at": "2026-10-21T13:10:00.000Z",
"expired_at": null,
"cancelled_at": null,
"cancelled_reason": null
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /negocios/{id}/desistimiento
Record a desistimiento
Before the escritura only (reservado or promesado): the stage becomes desistido, the unidades return to disponible and the negocio stops holding them. Records the reason and the outcome for the money paid (returned | retained | applied), stamped on the reserva cobro as its disposition (devuelto | perdido | aplicado). Requires leads:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ reservas and negocios; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
reason | string | sí | mín. 1, máx. 500 |
money_outcome | returned \ | retained \ | applied |
notes | string | null | — | máx. 2000 |
desisted_on | string | — | patrón ^\d{4}-\d{2}-\d{2}$ |
curl -X POST https://api.vitrinadev.com/api/v1/negocios/<id>/desistimiento \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"reason": "No obtuvo el crédito hipotecario",
"money_outcome": "returned"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000b01",
"display_id": "NG-3",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"reserva_id": "0199e3a0-0000-7000-8000-000000000a01",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"buyer_name": "Camila Rojas",
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"stage": "desistido",
"currency": "UF",
"total": 3510,
"uf_value_clp": 39532.12,
"reserved_at": "2026-10-21T13:10:00.000Z",
"created_at": "2026-10-21T13:10:00.000Z",
"updated_at": "2026-10-21T13:10:00.000Z",
"promesa_due_on": "2026-11-20",
"promesa_signed_on": null,
"escritura_due_on": null,
"escritura_signed_on": null,
"escritura_notary": null,
"entrega_due_on": null,
"entregado_on": null,
"desisted_on": "2026-12-02",
"desist_reason": "No obtuvo el crédito hipotecario",
"desist_money_outcome": "returned",
"desist_notes": null,
"milestone_alerted_key": null,
"next_deadline": null,
"buyers": [
{
"id": "0199e3a0-0000-7000-8000-000000000b11",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"contact_name": "Camila Rojas",
"role": "titular",
"position": 0
}
],
"units": [
{
"id": "0199e3a0-0000-7000-8000-000000000b21",
"property_id": "0199e3a0-0000-7000-8000-000000000401",
"property_display_id": "I-41",
"kind": "departamento",
"label": "Departamento 1203 · 3D2B 78 m²",
"unit_number": "1203",
"price": 3310,
"position": 0,
"released_at": null,
"status": "reservada"
},
{
"id": "0199e3a0-0000-7000-8000-000000000b22",
"property_id": "0199e3a0-0000-7000-8000-000000000402",
"property_display_id": "I-87",
"kind": "estacionamiento",
"label": "Estacionamiento E-12",
"unit_number": "E-12",
"price": 200,
"position": 1,
"released_at": null,
"status": "reservada"
}
],
"reserva": {
"id": "0199e3a0-0000-7000-8000-000000000a01",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"cotizacion_display_id": "CZ-12",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"co_buyer_contact_ids": [],
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"property_ids": [
"0199e3a0-0000-7000-8000-000000000401",
"0199e3a0-0000-7000-8000-000000000402"
],
"status": "paid",
"amount": 20,
"currency": "UF",
"amount_clp": 790642,
"uf_value_clp": 39532.12,
"expires_at": "2026-10-22T15:00:00.000Z",
"obligation_id": "0199e3a0-0000-7000-8000-000000000c01",
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T15:00:00.000Z",
"updated_at": "2026-10-20T15:00:00.000Z",
"paid_at": "2026-10-21T13:10:00.000Z",
"expired_at": null,
"cancelled_at": null,
"cancelled_reason": null
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /negocios/{id}/documents
A negocio’s document checklist
Every item with its status (missing → received → approved | rejected), the file (name, type, size; download with GET …/file), where it came from (the buyer in the chat, a staff upload, a signed document) and the reminders sent. Built from the proyecto’s list on first read. Requires leads:read. Only on a workspace that runs the Proyectos module; any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/negocios/<id>/documents \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"items": [
{
"id": "0199e3a0-0000-7000-8000-000000000f11",
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"key": "liquidaciones",
"label": "Últimas 3 liquidaciones de sueldo",
"description": null,
"required": true,
"position": 1,
"status": "received",
"file": {
"filename": "liquidaciones.pdf",
"mime": "application/pdf",
"size": 182331,
"uploaded_at": "2026-10-22T14:03:00.000Z"
},
"source": "chat",
"message_id": "88213",
"received_at": "2026-10-22T14:03:00.000Z",
"reviewed_at": null,
"reviewed_by": null,
"review_note": null,
"reminder_count": 1,
"last_reminded_at": "2026-10-21T13:00:00.000Z",
"created_at": "2026-10-21T13:10:00.000Z",
"updated_at": "2026-10-22T14:03:00.000Z"
}
],
"summary": {
"required": 4,
"received": 1,
"approved": 0,
"pending": 3
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /negocios/{id}/documents/{documentId}/file
Download a checklist document
The stored bytes, streamed through the API (nosniff, Cache-Control: private, no-store, sandbox CSP); every read is audited. Requires leads:read. Only on a workspace that runs the Proyectos module; any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
documentId | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/negocios/<id>/documents/<id>/file \
-H "Authorization: Bearer $VITRINA_KEY"Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /negocios/{id}/documents/{documentId}/file
Upload a document onto a checklist item
multipart/form-data with one file part (or the JSON file shape), at most 25 MB; images, PDF and office documents. The item becomes received; uploading again replaces it and clears the review. Requires leads:write. Only on a workspace that runs the Proyectos module; any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
documentId | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
filename | string | sí | mín. 1, máx. 255 |
content | string | sí | mín. 1, máx. 35000000 |
content_encoding | utf8 \ | base64 | — |
content_type | string | — | máx. 200 |
curl -X POST https://api.vitrinadev.com/api/v1/negocios/<id>/documents/<id>/file \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"filename": "liquidaciones.pdf",
"content": "JVBERi0xLjQK…",
"content_encoding": "base64"
}'Ejemplo de respuesta (201)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000f11",
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"key": "liquidaciones",
"label": "Últimas 3 liquidaciones de sueldo",
"description": null,
"required": true,
"position": 1,
"status": "received",
"file": {
"filename": "liquidaciones.pdf",
"mime": "application/pdf",
"size": 182331,
"uploaded_at": "2026-10-22T14:03:00.000Z"
},
"source": "chat",
"message_id": "88213",
"received_at": "2026-10-22T14:03:00.000Z",
"reviewed_at": null,
"reviewed_by": null,
"review_note": null,
"reminder_count": 1,
"last_reminded_at": "2026-10-21T13:00:00.000Z",
"created_at": "2026-10-21T13:10:00.000Z",
"updated_at": "2026-10-22T14:03:00.000Z"
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
POST /negocios/{id}/documents/{documentId}/review
Approve or reject a checklist document
A received item only (409 document_missing). Rejecting needs a note: the buyer gets it by WhatsApp (inside the 24 h window) with a request to send it again, and reminders resume. Requires leads:write. Only on a workspace that runs the Proyectos module; any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
documentId | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
status | approved \ | rejected | sí |
note | string | null | — | máx. 500 |
curl -X POST https://api.vitrinadev.com/api/v1/negocios/<id>/documents/<id>/review \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": "rejected",
"note": "La liquidación de agosto no se lee"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000f11",
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"key": "liquidaciones",
"label": "Últimas 3 liquidaciones de sueldo",
"description": null,
"required": true,
"position": 1,
"status": "rejected",
"file": {
"filename": "liquidaciones.pdf",
"mime": "application/pdf",
"size": 182331,
"uploaded_at": "2026-10-22T14:03:00.000Z"
},
"source": "chat",
"message_id": "88213",
"received_at": "2026-10-22T14:03:00.000Z",
"reviewed_at": null,
"reviewed_by": null,
"review_note": "La liquidación de agosto no se lee",
"reminder_count": 1,
"last_reminded_at": "2026-10-21T13:00:00.000Z",
"created_at": "2026-10-21T13:10:00.000Z",
"updated_at": "2026-10-22T14:03:00.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /negocios/{id}/entrega
Record the entrega
An escriturado negocio only: the stage becomes entregado (post-venta starts). Requires leads:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ reservas and negocios; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
delivered_on | string | — | patrón ^\d{4}-\d{2}-\d{2}$ |
curl -X POST https://api.vitrinadev.com/api/v1/negocios/<id>/entrega \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"delivered_on": "2027-06-15"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000b01",
"display_id": "NG-3",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"reserva_id": "0199e3a0-0000-7000-8000-000000000a01",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"buyer_name": "Camila Rojas",
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"stage": "entregado",
"currency": "UF",
"total": 3510,
"uf_value_clp": 39532.12,
"reserved_at": "2026-10-21T13:10:00.000Z",
"created_at": "2026-10-21T13:10:00.000Z",
"updated_at": "2026-10-21T13:10:00.000Z",
"promesa_due_on": "2026-11-20",
"promesa_signed_on": null,
"escritura_due_on": null,
"escritura_signed_on": null,
"escritura_notary": null,
"entrega_due_on": null,
"entregado_on": "2027-06-15",
"desisted_on": null,
"desist_reason": null,
"desist_money_outcome": null,
"desist_notes": null,
"milestone_alerted_key": null,
"next_deadline": null,
"buyers": [
{
"id": "0199e3a0-0000-7000-8000-000000000b11",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"contact_name": "Camila Rojas",
"role": "titular",
"position": 0
}
],
"units": [
{
"id": "0199e3a0-0000-7000-8000-000000000b21",
"property_id": "0199e3a0-0000-7000-8000-000000000401",
"property_display_id": "I-41",
"kind": "departamento",
"label": "Departamento 1203 · 3D2B 78 m²",
"unit_number": "1203",
"price": 3310,
"position": 0,
"released_at": null,
"status": "reservada"
},
{
"id": "0199e3a0-0000-7000-8000-000000000b22",
"property_id": "0199e3a0-0000-7000-8000-000000000402",
"property_display_id": "I-87",
"kind": "estacionamiento",
"label": "Estacionamiento E-12",
"unit_number": "E-12",
"price": 200,
"position": 1,
"released_at": null,
"status": "reservada"
}
],
"reserva": {
"id": "0199e3a0-0000-7000-8000-000000000a01",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"cotizacion_display_id": "CZ-12",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"co_buyer_contact_ids": [],
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"property_ids": [
"0199e3a0-0000-7000-8000-000000000401",
"0199e3a0-0000-7000-8000-000000000402"
],
"status": "paid",
"amount": 20,
"currency": "UF",
"amount_clp": 790642,
"uf_value_clp": 39532.12,
"expires_at": "2026-10-22T15:00:00.000Z",
"obligation_id": "0199e3a0-0000-7000-8000-000000000c01",
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T15:00:00.000Z",
"updated_at": "2026-10-20T15:00:00.000Z",
"paid_at": "2026-10-21T13:10:00.000Z",
"expired_at": null,
"cancelled_at": null,
"cancelled_reason": null
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /negocios/{id}/escritura
Record the escritura
A promesado negocio only: the stage becomes escriturado and the unidades vendida. The escritura is signed at the notary (notary), never e-signed. Sets the entrega deadline (entrega_due_on, else + the proyecto’s entrega_due_days). Requires leads:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ reservas and negocios; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
signed_on | string | — | patrón ^\d{4}-\d{2}-\d{2}$ |
notary | string | null | — | mín. 1, máx. 200 |
entrega_due_on | string | — | patrón ^\d{4}-\d{2}-\d{2}$ |
curl -X POST https://api.vitrinadev.com/api/v1/negocios/<id>/escritura \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"signed_on": "2027-04-30",
"notary": "Notaría Pérez, Santiago"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000b01",
"display_id": "NG-3",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"reserva_id": "0199e3a0-0000-7000-8000-000000000a01",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"buyer_name": "Camila Rojas",
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"stage": "escriturado",
"currency": "UF",
"total": 3510,
"uf_value_clp": 39532.12,
"reserved_at": "2026-10-21T13:10:00.000Z",
"created_at": "2026-10-21T13:10:00.000Z",
"updated_at": "2026-10-21T13:10:00.000Z",
"promesa_due_on": "2026-11-20",
"promesa_signed_on": null,
"escritura_due_on": null,
"escritura_signed_on": "2027-04-30",
"escritura_notary": "Notaría Pérez, Santiago",
"entrega_due_on": null,
"entregado_on": null,
"desisted_on": null,
"desist_reason": null,
"desist_money_outcome": null,
"desist_notes": null,
"milestone_alerted_key": null,
"next_deadline": {
"milestone": "promesa",
"due_on": "2026-11-20",
"overdue": false
},
"buyers": [
{
"id": "0199e3a0-0000-7000-8000-000000000b11",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"contact_name": "Camila Rojas",
"role": "titular",
"position": 0
}
],
"units": [
{
"id": "0199e3a0-0000-7000-8000-000000000b21",
"property_id": "0199e3a0-0000-7000-8000-000000000401",
"property_display_id": "I-41",
"kind": "departamento",
"label": "Departamento 1203 · 3D2B 78 m²",
"unit_number": "1203",
"price": 3310,
"position": 0,
"released_at": null,
"status": "reservada"
},
{
"id": "0199e3a0-0000-7000-8000-000000000b22",
"property_id": "0199e3a0-0000-7000-8000-000000000402",
"property_display_id": "I-87",
"kind": "estacionamiento",
"label": "Estacionamiento E-12",
"unit_number": "E-12",
"price": 200,
"position": 1,
"released_at": null,
"status": "reservada"
}
],
"reserva": {
"id": "0199e3a0-0000-7000-8000-000000000a01",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"cotizacion_display_id": "CZ-12",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"co_buyer_contact_ids": [],
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"property_ids": [
"0199e3a0-0000-7000-8000-000000000401",
"0199e3a0-0000-7000-8000-000000000402"
],
"status": "paid",
"amount": 20,
"currency": "UF",
"amount_clp": 790642,
"uf_value_clp": 39532.12,
"expires_at": "2026-10-22T15:00:00.000Z",
"obligation_id": "0199e3a0-0000-7000-8000-000000000c01",
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T15:00:00.000Z",
"updated_at": "2026-10-20T15:00:00.000Z",
"paid_at": "2026-10-21T13:10:00.000Z",
"expired_at": null,
"cancelled_at": null,
"cancelled_reason": null
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /negocios/{id}/pie-plan
Split the pie into cuotas
The pie (default: the accepted cotización’s pie minus the reserva already paid, in the negocio’s currency) in 1–36 monthly cuotas from first_due_on (default a month from today); the last cuota absorbs the rounding. Each cuota is a real_estate_pie obligation of the buyer, paid by its own link (GET …/cuotas/\{number\}/payment) or by transfer (the ledger’s matcher settles the oldest open cuota first). A UF cuota is charged at the day’s UF until money is applied to it. The buyer is reminded before and after each due day (/projects/\{id\}/pie-terms). 409 pie_plan_exists (pass replace while nothing is paid), pie_plan_has_payments, negocio_stage_conflict, uf_unavailable. Requires leads:write. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
installments | integer | — | ≥ 1, ≤ 36 |
total | number | — | > 0, ≤ 1000000000 |
first_due_on | string | — | patrón ^\d{4}-\d{2}-\d{2}$ |
replace | boolean | — |
curl -X POST https://api.vitrinadev.com/api/v1/negocios/<id>/pie-plan \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"installments": 12,
"first_due_on": "2026-11-20"
}'Ejemplo de respuesta (201)
{
"data": {
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"display_id": "NG-3",
"buyer_name": "Camila Rojas",
"project_name": "Parque Los Aromos",
"currency": "UF",
"total": 3510,
"reserva": {
"amount": 20,
"currency": "UF",
"amount_clp": 790642,
"paid_at": "2026-10-21T13:10:00.000Z"
},
"cuotas": [
{
"number": 1,
"due_on": "2026-11-20",
"amount": 58.5,
"currency": "UF",
"amount_clp": 2312629,
"obligation_id": "0199e3a0-0000-7000-8000-000000000c21",
"paid_clp": 0,
"outstanding_clp": 2312629,
"state": "pending",
"is_overdue": false
},
{
"number": 2,
"due_on": "2026-12-20",
"amount": 58.5,
"currency": "UF",
"amount_clp": 2312629,
"obligation_id": "0199e3a0-0000-7000-8000-000000000c22",
"paid_clp": 0,
"outstanding_clp": 2312629,
"state": "pending",
"is_overdue": false
}
],
"totals": {
"pie_clp": 27751548,
"paid_clp": 0,
"outstanding_clp": 27751548,
"overdue_clp": 0,
"cuotas_paid": 0,
"cuotas_overdue": 0
},
"next_due": {
"number": 1,
"due_on": "2026-11-20",
"amount": 58.5,
"currency": "UF",
"amount_clp": 2312629,
"obligation_id": "0199e3a0-0000-7000-8000-000000000c21",
"paid_clp": 0,
"outstanding_clp": 2312629,
"state": "pending",
"is_overdue": false
},
"as_of": "2026-10-22"
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
POST /negocios/{id}/promesa
Record the promesa
A reservado negocio only (409 negocio_stage_conflict otherwise): the stage becomes promesado, the unidades promesada, and the escritura deadline is set (escritura_due_on, else signed_on + the proyecto’s escritura_due_days). Requires leads:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ reservas and negocios; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
signed_on | string | — | patrón ^\d{4}-\d{2}-\d{2}$ |
escritura_due_on | string | — | patrón ^\d{4}-\d{2}-\d{2}$ |
curl -X POST https://api.vitrinadev.com/api/v1/negocios/<id>/promesa \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"signed_on": "2026-11-10"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000b01",
"display_id": "NG-3",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"reserva_id": "0199e3a0-0000-7000-8000-000000000a01",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"buyer_name": "Camila Rojas",
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"stage": "promesado",
"currency": "UF",
"total": 3510,
"uf_value_clp": 39532.12,
"reserved_at": "2026-10-21T13:10:00.000Z",
"created_at": "2026-10-21T13:10:00.000Z",
"updated_at": "2026-10-21T13:10:00.000Z",
"promesa_due_on": "2026-11-20",
"promesa_signed_on": "2026-11-10",
"escritura_due_on": "2027-05-09",
"escritura_signed_on": null,
"escritura_notary": null,
"entrega_due_on": null,
"entregado_on": null,
"desisted_on": null,
"desist_reason": null,
"desist_money_outcome": null,
"desist_notes": null,
"milestone_alerted_key": null,
"next_deadline": {
"milestone": "escritura",
"due_on": "2027-05-09",
"overdue": false
},
"buyers": [
{
"id": "0199e3a0-0000-7000-8000-000000000b11",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"contact_name": "Camila Rojas",
"role": "titular",
"position": 0
}
],
"units": [
{
"id": "0199e3a0-0000-7000-8000-000000000b21",
"property_id": "0199e3a0-0000-7000-8000-000000000401",
"property_display_id": "I-41",
"kind": "departamento",
"label": "Departamento 1203 · 3D2B 78 m²",
"unit_number": "1203",
"price": 3310,
"position": 0,
"released_at": null,
"status": "reservada"
},
{
"id": "0199e3a0-0000-7000-8000-000000000b22",
"property_id": "0199e3a0-0000-7000-8000-000000000402",
"property_display_id": "I-87",
"kind": "estacionamiento",
"label": "Estacionamiento E-12",
"unit_number": "E-12",
"price": 200,
"position": 1,
"released_at": null,
"status": "reservada"
}
],
"reserva": {
"id": "0199e3a0-0000-7000-8000-000000000a01",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"cotizacion_display_id": "CZ-12",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"co_buyer_contact_ids": [],
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"property_ids": [
"0199e3a0-0000-7000-8000-000000000401",
"0199e3a0-0000-7000-8000-000000000402"
],
"status": "paid",
"amount": 20,
"currency": "UF",
"amount_clp": 790642,
"uf_value_clp": 39532.12,
"expires_at": "2026-10-22T15:00:00.000Z",
"obligation_id": "0199e3a0-0000-7000-8000-000000000c01",
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T15:00:00.000Z",
"updated_at": "2026-10-20T15:00:00.000Z",
"paid_at": "2026-10-21T13:10:00.000Z",
"expired_at": null,
"cancelled_at": null,
"cancelled_reason": null
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /negocios/{id}/signatures
A negocio’s signing requests
Every request, newest first, with its status, the document hash, which files exist and the evidence trail (requested, code sent/verified, cédula and selfie submitted with their hashes, sent to the provider, signed — each with instant, IP and user agent). Requires leads:read. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/negocios/<id>/signatures \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000c11",
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"kind": "orden_reserva",
"provider": "documenso",
"status": "pending_identity",
"title": "Orden de reserva",
"signer_name": "Camila Rojas",
"signer_phone_hint": "+56•••••4567",
"document_sha256": "9f2c…",
"otp_channel": null,
"otp_verified_at": null,
"identity_submitted_at": null,
"signed_at": null,
"expires_at": "2026-10-29T15:00:00.000Z",
"cancelled_at": null,
"files": {
"unsigned": true,
"signed": false,
"certificate": false,
"id_front": false,
"selfie": false
},
"evidence": [
{
"at": "2026-10-22T15:00:00.000Z",
"event": "requested"
}
],
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_at": "2026-10-22T15:00:00.000Z"
}
]
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /negocios/{id}/signatures
Send a negocio document to sign
Generates the document (the proyecto’s template filled with the negocio, its cotización and reserva) as a branded PDF, freezes its SHA-256 and sends the buyer a WhatsApp link (deliver, default true, as the teammate; link is returned once to copy). On the link the buyer reads the PDF, types an SMS code, uploads a photo of the cédula and a selfie, and signs with the provider (Documenso, FES). The signed PDF and the certificate land on the negocio checklist and the ejecutivo is told. 409 signature_pending, negocio_stage_conflict, signing_not_configured. Requires leads:write (+ messages:send, conversations:write to deliver). Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
kind | orden_reserva | sí | |
deliver | boolean | — |
curl -X POST https://api.vitrinadev.com/api/v1/negocios/<id>/signatures \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"kind": "orden_reserva"
}'Ejemplo de respuesta (201)
{
"data": {
"signature": {
"id": "0199e3a0-0000-7000-8000-000000000c11",
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"kind": "orden_reserva",
"provider": "documenso",
"status": "pending_identity",
"title": "Orden de reserva",
"signer_name": "Camila Rojas",
"signer_phone_hint": "+56•••••4567",
"document_sha256": "9f2c…",
"otp_channel": null,
"otp_verified_at": null,
"identity_submitted_at": null,
"signed_at": null,
"expires_at": "2026-10-29T15:00:00.000Z",
"cancelled_at": null,
"files": {
"unsigned": true,
"signed": false,
"certificate": false,
"id_front": false,
"selfie": false
},
"evidence": [
{
"at": "2026-10-22T15:00:00.000Z",
"event": "requested"
}
],
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_at": "2026-10-22T15:00:00.000Z"
},
"link": "https://app.vitrinadev.com/firmar/q9Xc…",
"text": "Hola Camila, te enviamos tu orden de reserva para firmar: …",
"delivery": {
"status": "sent",
"reason": null,
"message_id": "88300",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"channel": "whatsapp"
}
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
POST /negocios/{id}/signatures/{signatureId}/cancel
Cancel a signing request
The link stops working and the provider envelope is cancelled. Requires leads:write. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
signatureId | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/negocios/<id>/signatures/<id>/cancel \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000c11",
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"kind": "orden_reserva",
"provider": "documenso",
"status": "cancelled",
"title": "Orden de reserva",
"signer_name": "Camila Rojas",
"signer_phone_hint": "+56•••••4567",
"document_sha256": "9f2c…",
"otp_channel": null,
"otp_verified_at": null,
"identity_submitted_at": null,
"signed_at": null,
"expires_at": "2026-10-29T15:00:00.000Z",
"cancelled_at": null,
"files": {
"unsigned": true,
"signed": false,
"certificate": false,
"id_front": false,
"selfie": false
},
"evidence": [
{
"at": "2026-10-22T15:00:00.000Z",
"event": "requested"
}
],
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_at": "2026-10-22T15:00:00.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /negocios/{id}/signatures/{signatureId}/files/{file}
Download a signing file
unsigned (what was sent), signed, certificate (the provider’s), id_front or selfie. Streamed, no-store, audited. Requires leads:read. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
signatureId | path | uuid | sí | |
file | path | unsigned \ | signed \ | certificate \ |
curl https://api.vitrinadev.com/api/v1/negocios/<id>/signatures/<id>/files/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /negocios/{id}/signatures/{signatureId}/resend
Send a new signing link
A live request only (409 signature_not_live); the previous link stops working. Requires leads:write. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
signatureId | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
deliver | boolean | — |
curl -X POST https://api.vitrinadev.com/api/v1/negocios/<id>/signatures/<id>/resend \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{}'Ejemplo de respuesta (200)
{
"data": {
"signature": {
"id": "0199e3a0-0000-7000-8000-000000000c11",
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"kind": "orden_reserva",
"provider": "documenso",
"status": "pending_identity",
"title": "Orden de reserva",
"signer_name": "Camila Rojas",
"signer_phone_hint": "+56•••••4567",
"document_sha256": "9f2c…",
"otp_channel": null,
"otp_verified_at": null,
"identity_submitted_at": null,
"signed_at": null,
"expires_at": "2026-10-29T15:00:00.000Z",
"cancelled_at": null,
"files": {
"unsigned": true,
"signed": false,
"certificate": false,
"id_front": false,
"selfie": false
},
"evidence": [
{
"at": "2026-10-22T15:00:00.000Z",
"event": "requested"
}
],
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_at": "2026-10-22T15:00:00.000Z"
},
"link": "https://app.vitrinadev.com/firmar/Zr3…",
"text": "…",
"delivery": {
"status": "sent",
"reason": null,
"message_id": "88301",
"conversation_id": null,
"channel": "whatsapp"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /negocios/{id}/statement
A negocio’s account statement
The estado de cuenta: the reserva and every cuota with what is paid, owed and overdue (from the ledger), the totals and the next cuota due. Requires leads:read. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/negocios/<id>/statement \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"display_id": "NG-3",
"buyer_name": "Camila Rojas",
"project_name": "Parque Los Aromos",
"currency": "UF",
"total": 3510,
"reserva": {
"amount": 20,
"currency": "UF",
"amount_clp": 790642,
"paid_at": "2026-10-21T13:10:00.000Z"
},
"cuotas": [
{
"number": 1,
"due_on": "2026-11-20",
"amount": 58.5,
"currency": "UF",
"amount_clp": 2312629,
"obligation_id": "0199e3a0-0000-7000-8000-000000000c21",
"paid_clp": 0,
"outstanding_clp": 2312629,
"state": "pending",
"is_overdue": false
},
{
"number": 2,
"due_on": "2026-12-20",
"amount": 58.5,
"currency": "UF",
"amount_clp": 2312629,
"obligation_id": "0199e3a0-0000-7000-8000-000000000c22",
"paid_clp": 0,
"outstanding_clp": 2312629,
"state": "pending",
"is_overdue": false
}
],
"totals": {
"pie_clp": 27751548,
"paid_clp": 0,
"outstanding_clp": 27751548,
"overdue_clp": 0,
"cuotas_paid": 0,
"cuotas_overdue": 0
},
"next_due": {
"number": 1,
"due_on": "2026-11-20",
"amount": 58.5,
"currency": "UF",
"amount_clp": 2312629,
"obligation_id": "0199e3a0-0000-7000-8000-000000000c21",
"paid_clp": 0,
"outstanding_clp": 2312629,
"state": "pending",
"is_overdue": false
},
"as_of": "2026-10-22"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /negocios/{id}/statement/pdf
The account statement as a PDF
Branded with the workspace’s paper. Requires leads:read. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/negocios/<id>/statement/pdf \
-H "Authorization: Bearer $VITRINA_KEY"Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /negocios/{id}/statement/send
Send the account statement to the buyer
The PDF on the buyer’s WhatsApp thread, inside Meta’s 24 h window (409 statement_window_closed, statement_no_thread). The buyer can also ask the agent for it. Requires leads:write. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/negocios/<id>/statement/send \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"sent": true,
"statement": {
"negocio_id": "0199e3a0-0000-7000-8000-000000000b01",
"display_id": "NG-3",
"buyer_name": "Camila Rojas",
"project_name": "Parque Los Aromos",
"currency": "UF",
"total": 3510,
"reserva": {
"amount": 20,
"currency": "UF",
"amount_clp": 790642,
"paid_at": "2026-10-21T13:10:00.000Z"
},
"cuotas": [
{
"number": 1,
"due_on": "2026-11-20",
"amount": 58.5,
"currency": "UF",
"amount_clp": 2312629,
"obligation_id": "0199e3a0-0000-7000-8000-000000000c21",
"paid_clp": 0,
"outstanding_clp": 2312629,
"state": "pending",
"is_overdue": false
},
{
"number": 2,
"due_on": "2026-12-20",
"amount": 58.5,
"currency": "UF",
"amount_clp": 2312629,
"obligation_id": "0199e3a0-0000-7000-8000-000000000c22",
"paid_clp": 0,
"outstanding_clp": 2312629,
"state": "pending",
"is_overdue": false
}
],
"totals": {
"pie_clp": 27751548,
"paid_clp": 0,
"outstanding_clp": 27751548,
"overdue_clp": 0,
"cuotas_paid": 0,
"cuotas_overdue": 0
},
"next_due": {
"number": 1,
"due_on": "2026-11-20",
"amount": 58.5,
"currency": "UF",
"amount_clp": 2312629,
"obligation_id": "0199e3a0-0000-7000-8000-000000000c21",
"paid_clp": 0,
"outstanding_clp": 2312629,
"state": "pending",
"is_overdue": false
},
"as_of": "2026-10-22"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /postventa/report
Post-venta report by proyecto, partida, estado de garantía or etapa
Casos grouped by group_by (project | partida | warranty_status | stage | priority | contratista): casos, observaciones, open and resolved, observaciones outside their garantía, the median days to resolve, the oldest open caso and the owners’ average 1 to 5 rating. Only tickets that carry a proyecto or an observación count. format=csv returns one row per observación (casos without one included) as a UTF-8 CSV with BOM for a spreadsheet. Requires tickets:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
group_by | query | project \ | partida \ | warranty_status \ |
project_id | query | uuid | no | |
from | query | string | no | date-time |
to | query | string | no | date-time |
format | query | json \ | csv | no |
curl https://api.vitrinadev.com/api/v1/postventa/report \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"key": "0199e3a0-0000-7000-8000-000000000101",
"label": "Vista Golf Departamentos",
"casos": 9,
"observaciones": 11,
"abiertos": 4,
"resueltos": 5,
"fuera_de_plazo": 1,
"mediana_dias_resolucion": 7,
"antiguedad_max_dias": 12.5,
"encuesta_promedio": 4.4
}
],
"meta": {
"group_by": "project"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /postventa/unit-owners
The unidades a contact owns
The owner registry the agent identifies a WhatsApp number against: live ownerships of the contact, with the dates their garantías start from. Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
contact_id | query | uuid | sí |
curl https://api.vitrinadev.com/api/v1/postventa/unit-owners \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"unit_owner_id": "0199e3a0-0000-7000-8000-000000000d01",
"property_id": "0199e3a0-0000-7000-8000-000000000401",
"display_id": "I-42",
"unit_number": "302",
"kind": "departamento",
"title": "Departamento 302 · Vista Golf Departamentos",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Vista Golf Departamentos",
"escritura_at": "2024-04-02",
"cbr_registered_at": "2024-04-20",
"delivered_at": "2024-05-10",
"recepcion_definitiva_at": "2024-03-15"
}
]
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /postventa/unit-owners
Register the owner of a unidad
Idempotent on (unidad, contact): a second call updates the dates it names. cbr_registered_at starts the 3-year terminaciones garantía; the proyecto’s recepcion_definitiva_at starts the 5- and 10-year ones. The entrega of a negocio writes this row when negocios ship. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
curl -X PUT https://api.vitrinadev.com/api/v1/postventa/unit-owners \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"property_id": "0199e3a0-0000-7000-8000-000000000401",
"contact_id": "0199e3a0-0000-7000-8000-000000000c01",
"escritura_at": "2024-04-02",
"cbr_registered_at": "2024-04-20",
"delivered_at": "2024-05-10"
}'Ejemplo de respuesta (201)
{
"data": {
"unit_owner_id": "0199e3a0-0000-7000-8000-000000000d01",
"property_id": "0199e3a0-0000-7000-8000-000000000401",
"display_id": "I-42",
"unit_number": "302",
"kind": "departamento",
"title": "Departamento 302 · Vista Golf Departamentos",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Vista Golf Departamentos",
"escritura_at": "2024-04-02",
"cbr_registered_at": "2024-04-20",
"delivered_at": "2024-05-10",
"recepcion_definitiva_at": "2024-03-15"
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /postventa/unit-owners/{id}
End an ownership
The unidad was sold on, or the row was a mistake. Casos already opened keep their unidad. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/postventa/unit-owners/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Responde: 204 · 400 · 401 · 403 · 404 · 409 · 429
GET /price-lists
List lista de precios versions
The versions of the proyectos’ listas de precios, newest first within each proyecto (without their prices: GET /price-lists/\{id\}). Filters: project_id, status (draft | published), current=true (only each proyecto’s current list). A version’s id is the stable price_list_version_id a cotización records. Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
project_id | query | uuid[] | no | |
status | query | draft \ | published[] | no |
current | query | boolean | no | |
limit | query | integer | no | ≥ 1, ≤ 200 |
offset | query | integer | null | no | ≥ 0 |
curl https://api.vitrinadev.com/api/v1/price-lists \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000501",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Parque Los Aromos"
},
"version_number": 2,
"status": "published",
"is_current": true,
"name": "Lista noviembre 2026",
"notes": null,
"based_on_version_id": "0199e3a0-0000-7000-8000-000000000500",
"entry_count": 200,
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:30:00.000Z",
"published_at": "2026-10-20T12:30:00.000Z",
"published_by": "0199e3a0-0000-7000-8000-0000000000bb",
"published_by_kind": "ui_member",
"superseded_at": null,
"superseded_by_version_id": null
}
],
"meta": {
"pagination": {
"total": 1,
"limit": 50,
"offset": 0
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /price-lists
Open a draft lista de precios
Opens the proyecto’s next version (v1, v2…) as a draft, by default with the current list’s prices copied in (each keeps who set it and when). One draft per proyecto: a second is a 409 price_list_draft_exists with the draft’s id in details.draft_id. Fill it with POST /price-lists/\{id\}/import or PATCH /price-lists/\{id\}/entries, then publish it. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
curl -X POST https://api.vitrinadev.com/api/v1/price-lists \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Lista noviembre 2026",
"copy_from": "current"
}'Ejemplo de respuesta (201)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000501",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Parque Los Aromos"
},
"version_number": 2,
"status": "draft",
"is_current": false,
"name": "Lista noviembre 2026",
"notes": null,
"based_on_version_id": "0199e3a0-0000-7000-8000-000000000500",
"entry_count": 200,
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:30:00.000Z",
"published_at": null,
"published_by": null,
"published_by_kind": null,
"superseded_at": null,
"superseded_by_version_id": null
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /price-lists/{id}
Discard a draft lista de precios
Deletes the draft and its prices; its version number is not reused. Drafts only: a published version is frozen (409 price_list_not_draft). Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/price-lists/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000501",
"deleted": true
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /price-lists/{id}
One lista de precios version, with its prices
Every unidad price of the version in UF and in CLP with the day’s UF (meta.uf_value), who set each price and when, and the price in the version it is compared with (a draft: the current list; a published version: the one it replaced) for a diff. Old versions stay readable forever. Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/price-lists/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000501",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Parque Los Aromos"
},
"version_number": 2,
"status": "published",
"is_current": true,
"name": "Lista noviembre 2026",
"notes": null,
"based_on_version_id": "0199e3a0-0000-7000-8000-000000000500",
"entry_count": 200,
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:30:00.000Z",
"published_at": "2026-10-20T12:30:00.000Z",
"published_by": "0199e3a0-0000-7000-8000-0000000000bb",
"published_by_kind": "ui_member",
"superseded_at": null,
"superseded_by_version_id": null,
"compared_with_version_id": "0199e3a0-0000-7000-8000-000000000500",
"summary": {
"entries": 200,
"added": 0,
"changed": 150,
"unchanged": 50,
"units_without_price": 0,
"removed_units": 0
},
"entries": [
{
"unit_id": "0199e3a0-0000-7000-8000-000000000401",
"display_id": "I-42",
"kind": "departamento",
"unit_number": "1203",
"title": "Departamento 1203 · Parque Los Aromos",
"floor": 12,
"unit_model": {
"id": "0199e3a0-0000-7000-8000-000000000201",
"name": "3D2B 78 m²"
},
"unit_status": "disponible",
"unit_removed": false,
"price_uf": 3310,
"price_clp": 130851317,
"previous_price_uf": 3250.5,
"source": "import",
"set_by": "0199e3a0-0000-7000-8000-0000000000bb",
"set_by_kind": "ui_member",
"set_at": "2026-10-20T12:10:00.000Z"
}
]
},
"meta": {
"uf_value": {
"clp": 39532.12,
"date": "2026-10-20"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /price-lists/{id}
Rename a draft lista de precios
Name and notes. Drafts only: a published version is frozen (409 price_list_not_draft). Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X PATCH https://api.vitrinadev.com/api/v1/price-lists/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Lista diciembre 2026"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000501",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Parque Los Aromos"
},
"version_number": 2,
"status": "draft",
"is_current": false,
"name": "Lista noviembre 2026",
"notes": null,
"based_on_version_id": "0199e3a0-0000-7000-8000-000000000500",
"entry_count": 200,
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:30:00.000Z",
"published_at": null,
"published_by": null,
"published_by_kind": null,
"superseded_at": null,
"superseded_by_version_id": null
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /price-lists/{id}/entries
Set prices in a draft lista de precios
Sets (or, with price_uf: null, removes) the price of one or more unidades of the proyecto, all or nothing; each price is stamped with who set it and when. Answers the whole version, with meta.changes. Drafts only: a published version is frozen (409 price_list_not_draft). Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X PATCH https://api.vitrinadev.com/api/v1/price-lists/<id>/entries \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"entries": [
{
"unit_id": "0199e3a0-0000-7000-8000-000000000401",
"price_uf": 3310
}
]
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000501",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Parque Los Aromos"
},
"version_number": 2,
"status": "published",
"is_current": true,
"name": "Lista noviembre 2026",
"notes": null,
"based_on_version_id": "0199e3a0-0000-7000-8000-000000000500",
"entry_count": 200,
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:30:00.000Z",
"published_at": "2026-10-20T12:30:00.000Z",
"published_by": "0199e3a0-0000-7000-8000-0000000000bb",
"published_by_kind": "ui_member",
"superseded_at": null,
"superseded_by_version_id": null,
"compared_with_version_id": "0199e3a0-0000-7000-8000-000000000500",
"summary": {
"entries": 200,
"added": 0,
"changed": 150,
"unchanged": 50,
"units_without_price": 0,
"removed_units": 0
},
"entries": [
{
"unit_id": "0199e3a0-0000-7000-8000-000000000401",
"display_id": "I-42",
"kind": "departamento",
"unit_number": "1203",
"title": "Departamento 1203 · Parque Los Aromos",
"floor": 12,
"unit_model": {
"id": "0199e3a0-0000-7000-8000-000000000201",
"name": "3D2B 78 m²"
},
"unit_status": "disponible",
"unit_removed": false,
"price_uf": 3310,
"price_clp": 130851317,
"previous_price_uf": 3250.5,
"source": "import",
"set_by": "0199e3a0-0000-7000-8000-0000000000bb",
"set_by_kind": "ui_member",
"set_at": "2026-10-20T12:10:00.000Z"
}
]
},
"meta": {
"uf_value": {
"clp": 39532.12,
"date": "2026-10-20"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /price-lists/{id}/import
Price import steps 2–3: dry run, then load prices into a draft
Loads prices from the inmobiliaria’s Excel or CSV (multipart: file, mapping as JSON text, dry_run, default_kind) or from JSON rows (the MCP path). dry_run defaults to true: the report says row by row what would be added, changed or left unchanged (with the draft’s and the current list’s price), and every error with its field; nothing is written. dry_run: false writes every row without an error in ONE transaction. A row is matched to a unidad of the proyecto by kind + number; a unidad the proyecto does not have is an error (load the stock first with POST /units/import). Unidades missing from the file keep the draft’s price (not_in_file). Drafts only: a published version is frozen (409 price_list_not_draft). Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/price-lists/<id>/import \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"rows": [
{
"Número": "1203",
"Tipo": "Depto",
"Precio UF": "3.310"
},
{
"Número": "E-12",
"Tipo": "Estacionamiento",
"Precio UF": 260
}
],
"mapping": {
"unit_number": "Número",
"kind": "Tipo",
"price_uf": "Precio UF"
},
"dry_run": true
}'Ejemplo de respuesta (200)
{
"data": {
"dry_run": true,
"price_list_version_id": "0199e3a0-0000-7000-8000-000000000501",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"mapping": {
"unit_number": "Número",
"kind": "Tipo",
"price_uf": "Precio UF"
},
"summary": {
"total_rows": 2,
"add": 0,
"change": 1,
"unchanged": 0,
"error": 1,
"not_in_file": 198
},
"rows": [
{
"row_number": 2,
"action": "change",
"unit_number": "1203",
"kind": "departamento",
"unit_id": "0199e3a0-0000-7000-8000-000000000401",
"display_id": "I-42",
"price_uf": 3310,
"draft_price_uf": 3250.5,
"current_price_uf": 3250.5,
"errors": []
},
{
"row_number": 3,
"action": "error",
"unit_number": "E-12",
"kind": "estacionamiento",
"unit_id": null,
"display_id": null,
"price_uf": 260,
"draft_price_uf": null,
"current_price_uf": null,
"errors": [
{
"field": "row",
"message": "La unidad estacionamiento E-12 no existe en este proyecto. Agrégala primero en Unidades."
}
]
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /price-lists/{id}/publish
Publish a lista de precios version
In one transaction: the proyecto’s current version is superseded (it stays readable), this draft becomes the published, current version, stamped with who published it and when, and every price is written onto its unidad (sale_price_amount in UF). The list is then the only writer of the proyecto’s unidad prices: sale_price_amount leaves a unidad’s protected_fields, a hand edit of the price answers 409 unit_price_owned_by_price_list, and the stock import ignores its price column. Unidades without a price in the version keep theirs (units_without_price). A cotización priced from an older version keeps that version’s prices. An empty draft is a 409 price_list_empty. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/price-lists/<id>/publish \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"price_list": {
"id": "0199e3a0-0000-7000-8000-000000000501",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Parque Los Aromos"
},
"version_number": 2,
"status": "published",
"is_current": true,
"name": "Lista noviembre 2026",
"notes": null,
"based_on_version_id": "0199e3a0-0000-7000-8000-000000000500",
"entry_count": 200,
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:30:00.000Z",
"published_at": "2026-10-20T12:30:00.000Z",
"published_by": "0199e3a0-0000-7000-8000-0000000000bb",
"published_by_kind": "ui_member",
"superseded_at": null,
"superseded_by_version_id": null
},
"superseded_version_id": "0199e3a0-0000-7000-8000-000000000500",
"units_priced": 200,
"units_changed": 150,
"skipped_removed": 0,
"units_without_price": 0
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /price-lists/import/columns
Price import step 1: read a file’s columns
Multipart, the file in a part named file (.xlsx, .xls or .csv, up to 20 MB). Returns the header, the first rows and the mapping we suggest for the three fields a price row needs (unit_number, kind, price_uf). Writes nothing: send the same file to POST /price-lists/\{id\}/import. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
curl -X POST https://api.vitrinadev.com/api/v1/price-lists/import/columns \
-H "Authorization: Bearer $VITRINA_KEY" \
-F "file=@/path/to/file.png"Ejemplo de respuesta (200)
{
"data": {
"format": "xlsx",
"sheet_name": "Lista",
"header": [
"N° Unidad",
"Tipo",
"Precio UF"
],
"row_count": 200,
"sample": [
[
"1203",
"Depto",
"3.310"
]
],
"suggested_mapping": {
"unit_number": "N° Unidad",
"kind": "Tipo",
"price_uf": "Precio UF"
},
"fields": [
{
"key": "price_uf",
"label": "Precio (UF)",
"required": true,
"description": "List price in UF, two decimals."
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /project-listings
List portal anuncios (Portal Inmobiliario, Yapo) and their proyecto
Anuncios (portal listings) of the workspace with how many leads arrived on each. mapped=false is the queue of anuncios waiting for a proyecto. Requires marketplace:read. A question or contact on a Portal Inmobiliario proyecto, or on a Yapo real-estate ad (matched by its Yapo ad id, adid), becomes a lead on the proyecto its anuncio is mapped to (lead.project_id), owned by one of its ejecutivos. An anuncio nobody has mapped yet is recorded on its first inquiry and that lead is flagged for mapping (project_id null, note on the lead). Only on the Proyectos module; callers whose role narrows proyectos are refused (403).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
mapped | query | true \ | false | no |
project_id | query | uuid | no | |
limit | query | integer | no | ≥ 1, ≤ 200 |
offset | query | integer | null | no | ≥ 0 |
curl https://api.vitrinadev.com/api/v1/project-listings \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000501",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"marketplace_account_id": "0199e3a0-0000-7000-8000-000000000601",
"external_id": "MLC1234567890",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"title": "Proyecto Parque Central, Ñuñoa",
"permalink": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"provider": "mercadolibre",
"lead_count": 4,
"unmapped_lead_count": 0
}
]
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /project-listings
Map a Portal Inmobiliario anuncio to a proyecto
Maps the portal's listing id to a proyecto ahead of its first inquiry. Idempotent on the anuncio: posting an already-seen id re-maps it, stamps the proyecto on its waiting leads and routes the unowned ones to the proyecto's ejecutivos. Requires marketplace:write. A question or contact on a Portal Inmobiliario proyecto, or on a Yapo real-estate ad (matched by its Yapo ad id, adid), becomes a lead on the proyecto its anuncio is mapped to (lead.project_id), owned by one of its ejecutivos. An anuncio nobody has mapped yet is recorded on its first inquiry and that lead is flagged for mapping (project_id null, note on the lead). Only on the Proyectos module; callers whose role narrows proyectos are refused (403).
curl -X POST https://api.vitrinadev.com/api/v1/project-listings \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"external_id": "MLC1234567890"
}'Ejemplo de respuesta (201)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000501",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"marketplace_account_id": "0199e3a0-0000-7000-8000-000000000601",
"external_id": "MLC1234567890",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"title": "Proyecto Parque Central, Ñuñoa",
"permalink": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"leads_mapped": 0
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /project-listings/{id}
Map or unmap a Portal Inmobiliario anuncio
Sets the proyecto of an anuncio (project_id), or clears it with null. Mapping stamps the proyecto on the leads waiting on the anuncio and routes the unowned ones to its ejecutivos; unmapping only affects leads that arrive afterwards. Requires marketplace:write. A question or contact on a Portal Inmobiliario proyecto, or on a Yapo real-estate ad (matched by its Yapo ad id, adid), becomes a lead on the proyecto its anuncio is mapped to (lead.project_id), owned by one of its ejecutivos. An anuncio nobody has mapped yet is recorded on its first inquiry and that lead is flagged for mapping (project_id null, note on the lead). Only on the Proyectos module; callers whose role narrows proyectos are refused (403).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X PATCH https://api.vitrinadev.com/api/v1/project-listings/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_id": "0199e3a0-0000-7000-8000-000000000101"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000501",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"marketplace_account_id": "0199e3a0-0000-7000-8000-000000000601",
"external_id": "MLC1234567890",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"title": "Proyecto Parque Central, Ñuñoa",
"permalink": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"leads_mapped": 3
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects
List proyectos
Live proyectos, newest first, every filter ANDed: comuna (accent- and case-insensitive), stage (etapa), subsidy (qualifies for any), sales_office_location_id, free text q. Each row carries unit_model_count and the stock summary units_total, units_available and price_from_uf (the «desde» in UF) and member_count (the team). Requires marketplace:read. A caller whose role narrows proyectos (project_visibility assigned = ejecutivo, sales_office = jefe de sala) only sees the proyectos it admits; any other answers 404, as if it did not exist. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
q | query | string | no | máx. 200 |
comuna | query | string[] | no | |
stage | query | en_blanco \ | en_verde \ | entrega_inmediata[] |
subsidy | query | DS19 \ | DS1 \ | DS49[] |
sales_office_location_id | query | uuid | no | |
limit | query | integer | no | ≥ 1, ≤ 200 |
offset | query | integer | null | no | ≥ 0 |
curl https://api.vitrinadev.com/api/v1/projects \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000101",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"name": "Parque Los Aromos",
"description": "Condominio de departamentos a pasos del metro.",
"region": "Metropolitana",
"comuna": "La Florida",
"address": "Av. Vicuña Mackenna 0000",
"stage": "en_verde",
"delivery_date": "2027-12-01",
"recepcion_definitiva_at": null,
"on_call_user_ids": [],
"subsidies": [
"DS19"
],
"sales_office_location_id": "0199e3a0-0000-7000-8000-000000000301",
"photos": [
"https://media.example.com/t/other/aromos-1.jpg"
],
"brochure_url": "https://media.example.com/t/other/aromos-brochure.pdf",
"meta_ad_ids": [
"120211111111111111"
],
"whatsapp_code": "RK482",
"visor_show_prices": false,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"unit_model_count": 1,
"units_total": 40,
"units_available": 12,
"price_from_uf": 3250.5,
"member_count": 2
}
],
"meta": {
"pagination": {
"total": 1,
"limit": 50,
"offset": 0
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /projects
Add a proyecto
Names are unique among the workspace’s live proyectos (409 otherwise). The sala de ventas is an active location of the workspace (GET /locations); one sala may serve several proyectos. Media fields (photos, brochure_url) are public URLs: upload the file with POST /tenant/media first and send its url. Requires marketplace:write. A caller whose role narrows proyectos (project_visibility assigned = ejecutivo, sales_office = jefe de sala) only sees the proyectos it admits; any other answers 404, as if it did not exist. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
curl -X POST https://api.vitrinadev.com/api/v1/projects \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Parque Los Aromos",
"comuna": "La Florida",
"region": "Metropolitana",
"stage": "en_verde",
"delivery_date": "2027-12-01",
"subsidies": [
"DS19"
],
"sales_office_location_id": "0199e3a0-0000-7000-8000-000000000301"
}'Ejemplo de respuesta (201)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"name": "Parque Los Aromos",
"description": "Condominio de departamentos a pasos del metro.",
"region": "Metropolitana",
"comuna": "La Florida",
"address": "Av. Vicuña Mackenna 0000",
"stage": "en_verde",
"delivery_date": "2027-12-01",
"recepcion_definitiva_at": null,
"on_call_user_ids": [],
"subsidies": [
"DS19"
],
"sales_office_location_id": "0199e3a0-0000-7000-8000-000000000301",
"photos": [
"https://media.example.com/t/other/aromos-1.jpg"
],
"brochure_url": "https://media.example.com/t/other/aromos-brochure.pdf",
"meta_ad_ids": [
"120211111111111111"
],
"whatsapp_code": "RK482",
"visor_show_prices": false,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"sales_office": {
"id": "0199e3a0-0000-7000-8000-000000000301",
"display_id": "B-2",
"name": "Sala de ventas La Florida"
},
"unit_models": [
{
"id": "0199e3a0-0000-7000-8000-000000000201",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"name": "3D2B 78 m²",
"description": "Esquina, con terraza en L.",
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"total_area_m2": 78.5,
"floor_plans": [
"https://media.example.com/t/other/planta-3d2b.pdf"
],
"renders": [
"https://media.example.com/t/other/render-3d2b.jpg"
],
"tour_360_url": "https://tour.example.com/3d2b",
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
]
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /projects/{id}
Remove a proyecto
Takes the proyecto and its tipologías out of every list. Requires marketplace:write. A caller whose role narrows proyectos (project_visibility assigned = ejecutivo, sales_office = jefe de sala) only sees the proyectos it admits; any other answers 404, as if it did not exist. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/projects/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Parque Los Aromos",
"deleted": true
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects/{id}
One proyecto, with its sala de ventas and tipologías
Requires marketplace:read. A caller whose role narrows proyectos (project_visibility assigned = ejecutivo, sales_office = jefe de sala) only sees the proyectos it admits; any other answers 404, as if it did not exist. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/projects/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"name": "Parque Los Aromos",
"description": "Condominio de departamentos a pasos del metro.",
"region": "Metropolitana",
"comuna": "La Florida",
"address": "Av. Vicuña Mackenna 0000",
"stage": "en_verde",
"delivery_date": "2027-12-01",
"recepcion_definitiva_at": null,
"on_call_user_ids": [],
"subsidies": [
"DS19"
],
"sales_office_location_id": "0199e3a0-0000-7000-8000-000000000301",
"photos": [
"https://media.example.com/t/other/aromos-1.jpg"
],
"brochure_url": "https://media.example.com/t/other/aromos-brochure.pdf",
"meta_ad_ids": [
"120211111111111111"
],
"whatsapp_code": "RK482",
"visor_show_prices": false,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"sales_office": {
"id": "0199e3a0-0000-7000-8000-000000000301",
"display_id": "B-2",
"name": "Sala de ventas La Florida"
},
"unit_models": [
{
"id": "0199e3a0-0000-7000-8000-000000000201",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"name": "3D2B 78 m²",
"description": "Esquina, con terraza en L.",
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"total_area_m2": 78.5,
"floor_plans": [
"https://media.example.com/t/other/planta-3d2b.pdf"
],
"renders": [
"https://media.example.com/t/other/render-3d2b.jpg"
],
"tour_360_url": "https://tour.example.com/3d2b",
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /projects/{id}
Edit a proyecto
Partial update; null clears a field. Media fields (photos, brochure_url) are public URLs: upload the file with POST /tenant/media first and send its url. Requires marketplace:write. A caller whose role narrows proyectos (project_visibility assigned = ejecutivo, sales_office = jefe de sala) only sees the proyectos it admits; any other answers 404, as if it did not exist. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X PATCH https://api.vitrinadev.com/api/v1/projects/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"stage": "entrega_inmediata"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"name": "Parque Los Aromos",
"description": "Condominio de departamentos a pasos del metro.",
"region": "Metropolitana",
"comuna": "La Florida",
"address": "Av. Vicuña Mackenna 0000",
"stage": "en_verde",
"delivery_date": "2027-12-01",
"recepcion_definitiva_at": null,
"on_call_user_ids": [],
"subsidies": [
"DS19"
],
"sales_office_location_id": "0199e3a0-0000-7000-8000-000000000301",
"photos": [
"https://media.example.com/t/other/aromos-1.jpg"
],
"brochure_url": "https://media.example.com/t/other/aromos-brochure.pdf",
"meta_ad_ids": [
"120211111111111111"
],
"whatsapp_code": "RK482",
"visor_show_prices": false,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"sales_office": {
"id": "0199e3a0-0000-7000-8000-000000000301",
"display_id": "B-2",
"name": "Sala de ventas La Florida"
},
"unit_models": [
{
"id": "0199e3a0-0000-7000-8000-000000000201",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"name": "3D2B 78 m²",
"description": "Esquina, con terraza en L.",
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"total_area_m2": 78.5,
"floor_plans": [
"https://media.example.com/t/other/planta-3d2b.pdf"
],
"renders": [
"https://media.example.com/t/other/render-3d2b.jpg"
],
"tour_360_url": "https://tour.example.com/3d2b",
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects/{id}/document-requirements
Get a proyecto’s document checklist
What every buyer of this proyecto is asked for, in order. A proyecto that states none gets the platform default (cédula, liquidaciones, cotizaciones AFP, pre-aprobación; plus the subsidy certificate when the proyecto takes DS19/DS1/DS49) and is_default: true. reminder_days: how often buyers are reminded of missing items. Requires marketplace:read. Only on a workspace that runs the Proyectos module; any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/projects/<id>/document-requirements \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"items": [
{
"key": "carnet",
"label": "Cédula de identidad (ambos lados)",
"required": true
},
{
"key": "liquidaciones",
"label": "Últimas 3 liquidaciones de sueldo",
"required": true
}
],
"is_default": false,
"reminder_days": 3
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /projects/{id}/document-requirements
Set a proyecto’s document checklist
Replaces the list (an empty list returns to the default). Existing negocios gain new items on their next read; items are never removed from a negocio. Requires marketplace:write. Only on a workspace that runs the Proyectos module; any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
items | any[] | sí | |
reminder_days | integer | — | ≥ 0, ≤ 60 |
curl -X PUT https://api.vitrinadev.com/api/v1/projects/<id>/document-requirements \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"key": "carnet",
"label": "Cédula de identidad (ambos lados)",
"required": true
},
{
"key": "liquidaciones",
"label": "Últimas 3 liquidaciones de sueldo",
"required": true
}
],
"reminder_days": 3
}'Ejemplo de respuesta (200)
{
"data": {
"items": [
{
"key": "carnet",
"label": "Cédula de identidad (ambos lados)",
"required": true
},
{
"key": "liquidaciones",
"label": "Últimas 3 liquidaciones de sueldo",
"required": true
}
],
"is_default": false,
"reminder_days": 3
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /projects/{id}/entrega-checklist
Back to the default entrega checklist
Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/projects/<id>/entrega-checklist \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"custom": false,
"sections": [
{
"key": "banos",
"title": "Baños",
"items": [
{
"key": "bano_artefactos",
"label": "WC, lavamanos y ducha",
"partida": "instalaciones_sanitarias"
}
]
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects/{id}/entrega-checklist
The proyecto’s entrega checklist
Its own list when it has one (custom: true), else the platform default. Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/projects/<id>/entrega-checklist \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"custom": false,
"sections": [
{
"key": "banos",
"title": "Baños",
"items": [
{
"key": "bano_artefactos",
"label": "WC, lavamanos y ducha",
"partida": "instalaciones_sanitarias"
}
]
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /projects/{id}/entrega-checklist
Set the proyecto’s own entrega checklist
Replaces the list as a whole; the next acta of the proyecto is born from it (actas already open keep theirs). Section and item keys are unique. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X PUT https://api.vitrinadev.com/api/v1/projects/<id>/entrega-checklist \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"sections": [
{
"key": "banos",
"title": "Baños",
"items": [
{
"key": "bano_artefactos",
"label": "WC, lavamanos y ducha",
"partida": "instalaciones_sanitarias"
}
]
}
]
}'Ejemplo de respuesta (200)
{
"data": {
"custom": true,
"sections": [
{
"key": "banos",
"title": "Baños",
"items": [
{
"key": "bano_artefactos",
"label": "WC, lavamanos y ducha",
"partida": "instalaciones_sanitarias"
}
]
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects/{id}/floor-plans
List a proyecto’s floor plans
The proyecto’s plans in display order (sort_order, then floor, then name), each with the unidades placed on it as polygons normalised to the image. The plans feed the embeddable floor-plan visor, which colours each placed unidad by its live status on the inmobiliaria’s own site; whether it shows prices is the proyecto’s visor_show_prices. Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/projects/<id>/floor-plans \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000501",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Piso 12",
"floor": 12,
"image_url": "https://media.example.com/t/other/aromos-piso-12.png",
"image_width": 1600,
"image_height": 1000,
"sort_order": 12,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"units": [
{
"unit_id": "0199e3a0-0000-7000-8000-000000000401",
"shape": [
[
0.1,
0.2
],
[
0.3,
0.2
],
[
0.3,
0.45
],
[
0.1,
0.45
]
]
}
]
}
]
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /projects/{id}/floor-plans
Add a floor plan to a proyecto
A plan image (a floor, a planta tipo, a site plan of casas). Upload the image with POST /tenant/media first and send its url; send its pixel size too so the visor reserves the aspect ratio. The name is unique inside the proyecto (409 otherwise). Place unidades with PUT /floor-plans/\{id\}/units. The plans feed the embeddable floor-plan visor, which colours each placed unidad by its live status on the inmobiliaria’s own site; whether it shows prices is the proyecto’s visor_show_prices. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/projects/<id>/floor-plans \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Piso 12",
"floor": 12,
"image_url": "https://media.example.com/t/other/aromos-piso-12.png",
"image_width": 1600,
"image_height": 1000,
"sort_order": 12
}'Ejemplo de respuesta (201)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000501",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Piso 12",
"floor": 12,
"image_url": "https://media.example.com/t/other/aromos-piso-12.png",
"image_width": 1600,
"image_height": 1000,
"sort_order": 12,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"units": [
{
"unit_id": "0199e3a0-0000-7000-8000-000000000401",
"shape": [
[
0.1,
0.2
],
[
0.3,
0.2
],
[
0.3,
0.45
],
[
0.1,
0.45
]
]
}
]
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects/{id}/marketing-kit
Read a proyecto’s marketing kit
The proyecto’s kit (listing copy, Instagram posts, WhatsApp broadcast message) and the source facts it is written from, so a person’s own agent can write copy in another voice and send it back with PATCH. kit is null before the first generation. Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. A proyecto outside the caller’s proyectos is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/projects/<id>/marketing-kit \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"kit": null,
"source": {}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /projects/{id}/marketing-kit
Edit a proyecto’s marketing kit
Replaces whole sections (listing, instagram, whatsapp); the others stay. whatsapp.message is one paragraph of at most 500 characters (it fills a template variable). 409 kit_missing before the first generation. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. A proyecto outside the caller’s proyectos is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X PATCH https://api.vitrinadev.com/api/v1/projects/<id>/marketing-kit \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"whatsapp": {
"message": "Parque Los Aromos, en La Florida: en verde, entrega estimada marzo de 2027. Desde 2.890 UF. Escríbenos y coordinamos una visita a la sala de ventas."
}
}'Ejemplo de respuesta (200)
{
"data": {}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects/{id}/marketing-kit/audience
Who a kit broadcast would reach
Counts only, no people: the leads about the proyecto that inquired through Vitrina, how many were already reached this week (one kit broadcast per contact per 7 days), how many opted out of marketing, who would receive it, and whether the approved novedad_proyecto template is on the number. Portal, import, manual and campaign leads are never included. Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. A proyecto outside the caller’s proyectos is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/projects/<id>/marketing-kit/audience \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"matched": 120,
"capped": 8,
"opted_out": 5,
"eligible": 107,
"ready": true,
"issue": null
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /projects/{id}/marketing-kit/broadcast
Send a proyecto’s kit message by WhatsApp
Sends the kit’s whatsapp.message to the leads of GET .../audience as ONE paced marketing campaign with the approved novedad_proyecto template, so STOP, contact hours and Meta’s limits apply and the results show in Campañas. A person’s decision: it never runs by itself. 409 kit_missing (no kit), no_channel / no_template (WhatsApp or the approved template is missing) or no_recipients. Requires campaigns:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. A proyecto outside the caller’s proyectos is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/projects/<id>/marketing-kit/broadcast \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (201)
{
"data": {
"campaign_id": "0199e3a0-0000-7000-8000-000000000c01",
"recipients": 107
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
POST /projects/{id}/marketing-kit/generate
Generate a proyecto’s marketing kit
Writes the kit from the proyecto’s data and media: name, comuna, etapa, entrega, subsidios, each tipología with its m² and cheapest disponible UF price, photos and renders. No model is used; the copy arranges facts the inmobiliaria already keeps, in the workspace’s tú / usted register. Generating again REPLACES the content, edits included. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. A proyecto outside the caller’s proyectos is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/projects/<id>/marketing-kit/generate \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (201)
{
"data": {
"kit": {
"id": "0199e3a0-0000-7000-8000-000000000a01",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"content": {
"listing": {
"headline": "Parque Los Aromos: departamentos en La Florida",
"summary": "Parque Los Aromos, en La Florida. En verde, entrega estimada marzo de 2027. Desde 2.890 UF.",
"body": "Departamentos pensados para vivir cerca del parque.\n\nTipologías disponibles:\n- 3D2B, 3 dormitorios, 2 baños, 78 m² desde 3.250 UF\n\nAgenda tu visita a la sala de ventas.",
"highlights": [
"Etapa: En verde",
"Entrega estimada marzo de 2027",
"Desde 2.890 UF"
]
},
"instagram": [
{
"caption": "Conoce Parque Los Aromos, en La Florida. En verde, entrega estimada marzo de 2027. Desde 2.890 UF. Agenda tu visita a la sala de ventas.",
"hashtags": [
"parquelosaromos",
"laflorida",
"departamentos"
],
"image_url": "https://media.example.com/aromos/fachada.jpg"
}
],
"whatsapp": {
"message": "Parque Los Aromos, en La Florida: en verde, entrega estimada marzo de 2027. Desde 2.890 UF. Escríbenos y coordinamos una visita a la sala de ventas."
}
},
"generated_at": "2026-10-21T12:00:00.000Z",
"generated_by": null,
"edited_at": null,
"edited_by": null,
"created_at": "2026-10-21T12:00:00.000Z",
"updated_at": "2026-10-21T12:00:00.000Z"
},
"source": {}
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects/{id}/members
List the ejecutivos of a proyecto
The members assigned to this proyecto, in the order they joined it. An ejecutivo on a role with project_visibility: assigned sees only the leads of the proyectos they are assigned to, and a new lead about the proyecto (lead.project_id) with no owner is owned by one of them, round-robin, through the assignment chain. Requires marketplace:read. A caller whose role narrows proyectos (project_visibility assigned = ejecutivo, sales_office = jefe de sala) only sees the proyectos it admits; any other answers 404, as if it did not exist. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/projects/<id>/members \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"user_id": "0199e3a0-0000-7000-8000-000000000401",
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z"
}
]
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /projects/{id}/members
Assign an ejecutivo to a proyecto
Assigns an ACTIVE member of this workspace (400 otherwise). Idempotent: assigning someone already on the team returns their row. The member sees the proyecto’s leads on their next request and joins its lead rotation. Requires memberships:write. A caller whose role narrows proyectos (project_visibility assigned = ejecutivo, sales_office = jefe de sala) only sees the proyectos it admits; any other answers 404, as if it did not exist. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
user_id | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/projects/<id>/members \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"user_id": "0199e3a0-0000-7000-8000-000000000401"
}'Ejemplo de respuesta (201)
{
"data": {
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"user_id": "0199e3a0-0000-7000-8000-000000000401",
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z"
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /projects/{id}/members/{userId}
Unassign an ejecutivo from a proyecto
Takes the member off the proyecto’s team: they stop seeing its leads (except the ones they own) and leave its rotation. 404 when they were not on it. Requires memberships:write. A caller whose role narrows proyectos (project_visibility assigned = ejecutivo, sales_office = jefe de sala) only sees the proyectos it admits; any other answers 404, as if it did not exist. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
userId | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/projects/<id>/members/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"user_id": "0199e3a0-0000-7000-8000-000000000401",
"deleted": true
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects/{id}/milestone-terms
Get a proyecto’s milestone deadlines
The default deadlines a new negocio of this proyecto gets: the promesa promesa_due_days after the reserva (default 30), the escritura escritura_due_days after the promesa and the entrega entrega_due_days after the escritura (null = no default). Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ reservas and negocios; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/projects/<id>/milestone-terms \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"promesa_due_days": 30,
"escritura_due_days": 180,
"entrega_due_days": 60
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /projects/{id}/milestone-terms
Set a proyecto’s milestone deadlines
Applies to deadlines set afterwards (a new negocio, a promesa or escritura recorded later); existing deadlines are not moved. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ reservas and negocios; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X PUT https://api.vitrinadev.com/api/v1/projects/<id>/milestone-terms \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"promesa_due_days": 30,
"escritura_due_days": 180,
"entrega_due_days": 60
}'Ejemplo de respuesta (200)
{
"data": {
"promesa_due_days": 30,
"escritura_due_days": 180,
"entrega_due_days": 60
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects/{id}/obra-updates
A proyecto’s obra progress posts
Newest first. Requires marketplace:read. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/projects/<id>/obra-updates \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000e01",
"project_id": "0199e3a0-0000-7000-8000-000000000a01",
"title": "Terminaciones piso 6",
"note": "Se instalaron los pisos flotantes y se pintó el hall.",
"photos": [
{
"index": 0,
"filename": "hall.jpg",
"mime": "image/jpeg",
"size": 482113
}
],
"posted_by": "0199e3a0-0000-7000-8000-000000000f01",
"notified_at": null,
"notified_count": 0,
"created_at": "2026-10-22T14:05:00.000Z"
}
]
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /projects/{id}/obra-updates
Post an obra progress update
A title and a note; add photos with …/photos (up to 8), then tell the buyers with …/announce. Buyers can ask for the latest post and its photos on WhatsApp at any time. Requires marketplace:write. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
title | string | sí | mín. 1, máx. 140 |
note | string | null | — | máx. 2000 |
curl -X POST https://api.vitrinadev.com/api/v1/projects/<id>/obra-updates \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Terminaciones piso 6",
"note": "Se instalaron los pisos flotantes."
}'Ejemplo de respuesta (201)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000e01",
"project_id": "0199e3a0-0000-7000-8000-000000000a01",
"title": "Terminaciones piso 6",
"note": "Se instalaron los pisos flotantes y se pintó el hall.",
"photos": [
{
"index": 0,
"filename": "hall.jpg",
"mime": "image/jpeg",
"size": 482113
}
],
"posted_by": "0199e3a0-0000-7000-8000-000000000f01",
"notified_at": null,
"notified_count": 0,
"created_at": "2026-10-22T14:05:00.000Z"
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /projects/{id}/obra-updates/{updateId}
Remove an obra post
Buyers no longer see it. Requires marketplace:write. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
updateId | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/projects/<id>/obra-updates/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Responde: 204 · 400 · 401 · 403 · 404 · 409 · 429
POST /projects/{id}/obra-updates/{updateId}/announce
Tell the proyecto’s buyers about an obra post
A WhatsApp message to every buyer with a live negocio in the proyecto, inside Meta’s 24 h window only: a buyer whose window is closed is counted in window_closed, not messaged, and can still ask for the post. Once per post (409 obra_already_announced). Requires marketplace:write. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
updateId | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/projects/<id>/obra-updates/<id>/announce \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"buyers": 14,
"sent": 5,
"window_closed": 9,
"other": 0
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /projects/{id}/obra-updates/{updateId}/photos
Add a photo to an obra post
multipart/form-data with one file part (or the JSON file shape), JPG, PNG or WebP up to 10 MB; at most 8 photos per post. Requires marketplace:write. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
updateId | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
filename | string | sí | mín. 1, máx. 255 |
content | string | sí | mín. 1, máx. 35000000 |
content_encoding | utf8 \ | base64 | — |
content_type | string | — | máx. 200 |
curl -X POST https://api.vitrinadev.com/api/v1/projects/<id>/obra-updates/<id>/photos \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"filename": "hall.jpg",
"content": "/9j/4AAQSkZJRg…",
"content_encoding": "base64"
}'Ejemplo de respuesta (201)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000e01",
"project_id": "0199e3a0-0000-7000-8000-000000000a01",
"title": "Terminaciones piso 6",
"note": "Se instalaron los pisos flotantes y se pintó el hall.",
"photos": [
{
"index": 0,
"filename": "hall.jpg",
"mime": "image/jpeg",
"size": 482113
}
],
"posted_by": "0199e3a0-0000-7000-8000-000000000f01",
"notified_at": null,
"notified_count": 0,
"created_at": "2026-10-22T14:05:00.000Z"
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /projects/{id}/obra-updates/{updateId}/photos/{index}
Remove a photo from an obra post
Requires marketplace:write. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
updateId | path | uuid | sí | |
index | path | integer | null | no | ≥ 0, ≤ 7 |
curl -X DELETE https://api.vitrinadev.com/api/v1/projects/<id>/obra-updates/<id>/photos/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000e01",
"project_id": "0199e3a0-0000-7000-8000-000000000a01",
"title": "Terminaciones piso 6",
"note": "Se instalaron los pisos flotantes y se pintó el hall.",
"photos": [
{
"index": 0,
"filename": "hall.jpg",
"mime": "image/jpeg",
"size": 482113
}
],
"posted_by": "0199e3a0-0000-7000-8000-000000000f01",
"notified_at": null,
"notified_count": 0,
"created_at": "2026-10-22T14:05:00.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects/{id}/obra-updates/{updateId}/photos/{index}
Read an obra photo
The image bytes. Requires marketplace:read. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
updateId | path | uuid | sí | |
index | path | integer | null | no | ≥ 0, ≤ 7 |
curl https://api.vitrinadev.com/api/v1/projects/<id>/obra-updates/<id>/photos/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects/{id}/pie-terms
Get a proyecto’s cuota reminders
When buyers are reminded of a pie cuota. Requires marketplace:read. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/projects/<id>/pie-terms \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"reminder_days_before": 3,
"reminder_days_after": 2
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /projects/{id}/pie-terms
Set a proyecto’s cuota reminders
Requires marketplace:write. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X PUT https://api.vitrinadev.com/api/v1/projects/<id>/pie-terms \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"reminder_days_before": 3,
"reminder_days_after": 2
}'Ejemplo de respuesta (200)
{
"data": {
"reminder_days_before": 3,
"reminder_days_after": 2
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects/{id}/publication-readiness
Check a proyecto before publishing it to Portal Inmobiliario
Dry run: what the portal would refuse, with nothing sent. field_errors is keyed by the field to fix (a proyecto field, models.<tipología>.<field>, price, comuna, photos, seller_contact). A tipología needs its dormitorios, baños, superficies (útil, terraza, total) and a price in the published lista; its orientation, floor and estacionamientos come from its unidades, and gastos comunes from the proyecto’s unidades. Requires marketplace:read. The proyecto is ONE listing in the portal’s «Proyectos» category and each tipología a variation of it, with the «desde» price (UF, from the published lista de precios) and the stock (disponible unidades) of that tipología. The listing is the anuncio that maps inbound leads to the proyecto, so its leads land on the proyecto with no mapping step. Only on the Proyectos module.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
account_id | query | uuid | sí |
curl https://api.vitrinadev.com/api/v1/projects/<id>/publication-readiness \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"ready": false,
"field_errors": {
"models.3D2B.orientation": "Falta «Orientación (de sus unidades)» en la tipología «3D2B»."
},
"models_listed": 3,
"units_available": 41,
"price_from_uf": 2890
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects/{id}/publications
List a proyecto’s Portal Inmobiliario anuncios
The anuncios of the proyecto with the portal’s state (portal_state), the last push and its error. Requires marketplace:read. The proyecto is ONE listing in the portal’s «Proyectos» category and each tipología a variation of it, with the «desde» price (UF, from the published lista de precios) and the stock (disponible unidades) of that tipología. The listing is the anuncio that maps inbound leads to the proyecto, so its leads land on the proyecto with no mapping step. Only on the Proyectos module.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/projects/<id>/publications \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000501",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"marketplace_account_id": "0199e3a0-0000-7000-8000-000000000601",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"provider": "mercadolibre",
"external_id": "MLC1234567890",
"title": "Parque Central",
"permalink": "https://departamento.mercadolibre.cl/MLC-1234567890-parque-central-_JM",
"origin": "vitrina",
"status": "published",
"listing_type": "gold_premium",
"portal_state": "listed",
"portal_state_at": "2026-10-20T12:00:00.000Z",
"paused_by_vitrina": false,
"tipologias_listed": 1,
"last_published_at": "2026-10-20T12:00:00.000Z",
"last_synced_at": "2026-10-20T12:00:00.000Z",
"last_error": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
]
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /projects/{id}/publications
Publish a proyecto and its tipologías to Portal Inmobiliario
Lists the proyecto, or refreshes its live listing (outcome: updated). After that the listing follows the proyecto: an edit of the proyecto, a tipología or a unidad, and a new published lista de precios, push the content (price «desde» and stock per tipología); when no unidad is disponible the listing is paused, and resumed when stock returns; removing the proyecto closes it (final on the portal). A pause or close on the portal is recorded as portal_state and never changes a unidad’s status. Errors (422), each with field_errors: portal_listing_incomplete (nothing was sent), portal_no_package (the account has no developments pack with cupo, or lacks the developments permission: each pack allows one publication), portal_listing_rejected (the portal refused it; details.causes verbatim). Requires marketplace:write. The proyecto is ONE listing in the portal’s «Proyectos» category and each tipología a variation of it, with the «desde» price (UF, from the published lista de precios) and the stock (disponible unidades) of that tipología. The listing is the anuncio that maps inbound leads to the proyecto, so its leads land on the proyecto with no mapping step. Only on the Proyectos module.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/projects/<id>/publications \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"account_id": "0199e3a0-0000-7000-8000-000000000601"
}'Ejemplo de respuesta (201)
{
"data": {
"outcome": "published",
"publication": {
"id": "0199e3a0-0000-7000-8000-000000000501",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"marketplace_account_id": "0199e3a0-0000-7000-8000-000000000601",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"provider": "mercadolibre",
"external_id": "MLC1234567890",
"title": "Parque Central",
"permalink": "https://departamento.mercadolibre.cl/MLC-1234567890-parque-central-_JM",
"origin": "vitrina",
"status": "published",
"listing_type": "gold_premium",
"portal_state": "listed",
"portal_state_at": "2026-10-20T12:00:00.000Z",
"paused_by_vitrina": false,
"tipologias_listed": 1,
"last_published_at": "2026-10-20T12:00:00.000Z",
"last_synced_at": "2026-10-20T12:00:00.000Z",
"last_error": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /projects/{id}/publications/{publicationId}
Close a proyecto’s listing on Portal Inmobiliario
Closes the listing on the portal (final there: publishing again creates a new one). The proyecto and its unidades are untouched. Requires marketplace:write. The proyecto is ONE listing in the portal’s «Proyectos» category and each tipología a variation of it, with the «desde» price (UF, from the published lista de precios) and the stock (disponible unidades) of that tipología. The listing is the anuncio that maps inbound leads to the proyecto, so its leads land on the proyecto with no mapping step. Only on the Proyectos module.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
publicationId | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/projects/<id>/publications/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000501",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"marketplace_account_id": "0199e3a0-0000-7000-8000-000000000601",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"provider": "mercadolibre",
"external_id": "MLC1234567890",
"title": "Parque Central",
"permalink": "https://departamento.mercadolibre.cl/MLC-1234567890-parque-central-_JM",
"origin": "vitrina",
"status": "deleted",
"listing_type": "gold_premium",
"portal_state": "withdrawn",
"portal_state_at": "2026-10-20T12:00:00.000Z",
"paused_by_vitrina": false,
"tipologias_listed": 1,
"last_published_at": "2026-10-20T12:00:00.000Z",
"last_synced_at": "2026-10-20T12:00:00.000Z",
"last_error": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects/{id}/reserva-terms
Get a proyecto’s reserva terms
What a reserva of this proyecto costs (amount in currency, UF or CLP; null = stated on each reserva) and how long it holds the unidades bloqueada (hold_hours, default 48). Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ reservas and negocios; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/projects/<id>/reserva-terms \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"amount": 20,
"currency": "UF",
"hold_hours": 48
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /projects/{id}/reserva-terms
Set a proyecto’s reserva terms
Sets the default reserva amount (UF or CLP; both null to state it on each reserva) and the hold in hours (1–720). Applies to reservas started afterwards. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ reservas and negocios; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X PUT https://api.vitrinadev.com/api/v1/projects/<id>/reserva-terms \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 20,
"currency": "UF",
"hold_hours": 48
}'Ejemplo de respuesta (200)
{
"data": {
"amount": 20,
"currency": "UF",
"hold_hours": 48
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /projects/{id}/signing-templates/{kind}
Reset a proyecto’s signing template
Back to the platform text. Requires marketplace:write. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
kind | path | orden_reserva | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/projects/<id>/signing-templates/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"kind": "orden_reserva",
"title": "Orden de reserva",
"body": "# Orden de reserva\n\nEn {{ciudad}}, el {{fecha}}, {{comprador_nombre}} reserva…",
"is_default": true,
"placeholders": [
"inmobiliaria",
"proyecto",
"comprador_nombre",
"unidades",
"precio_total"
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects/{id}/signing-templates/{kind}
Get a proyecto’s signing template
The text of a signable document (the orden de reserva) with its {{placeholders}}; is_default when the proyecto uses the platform text. Requires marketplace:read. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
kind | path | orden_reserva | sí |
curl https://api.vitrinadev.com/api/v1/projects/<id>/signing-templates/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"kind": "orden_reserva",
"title": "Orden de reserva",
"body": "# Orden de reserva\n\nEn {{ciudad}}, el {{fecha}}, {{comprador_nombre}} reserva…",
"is_default": true,
"placeholders": [
"inmobiliaria",
"proyecto",
"comprador_nombre",
"unidades",
"precio_total"
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /projects/{id}/signing-templates/{kind}
Set a proyecto’s signing template
Title and body (headings with #, paragraphs, {{placeholders}}); it must name the buyer ({{comprador_nombre}}). Applies to documents generated afterwards; a request already sent keeps its PDF. Requires marketplace:write. Only on a workspace that runs the Proyectos module; an ejecutivo only reaches their proyectos’ negocios (404 otherwise).
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí | |
kind | path | orden_reserva | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
title | string | sí | mín. 1, máx. 120 |
body | string | sí | mín. 20, máx. 20000 |
curl -X PUT https://api.vitrinadev.com/api/v1/projects/<id>/signing-templates/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Orden de reserva",
"body": "# Orden de reserva\n\nEn {{ciudad}}, el {{fecha}}, {{comprador_nombre}} reserva…"
}'Ejemplo de respuesta (200)
{
"data": {
"kind": "orden_reserva",
"title": "Orden de reserva",
"body": "# Orden de reserva\n\nEn {{ciudad}}, el {{fecha}}, {{comprador_nombre}} reserva…",
"is_default": false,
"placeholders": [
"inmobiliaria",
"proyecto",
"comprador_nombre",
"unidades",
"precio_total"
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects/{id}/toctoc
A proyecto’s TocToc publishing payload and state
The payload a hand-over of the proyecto to TocToc carries (the proyecto, its tipologías and the live stock behind each, versioned by schema), what the listing still lacks (issues, empty = ready), and where the proyecto stands on TocToc (publication, null = a draft). Requires marketplace:read. TocToc offers no API or webhook (spike #4427): its lead notifications arrive by the forwarded email at the workspace’s lead door, and publishing is assisted (export the payload, record the code TocToc returns). Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Refused (403) to a caller whose role narrows proyectos.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/projects/<id>/toctoc \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"publication": {
"id": "0199e3a0-0000-7000-8000-000000000803",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"status": "live",
"external_ref": "TT-48213",
"notes": null,
"submitted_at": "2026-10-20T12:00:00.000Z",
"live_at": "2026-10-20T12:00:00.000Z",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
},
"payload": {
"schema": "vitrina.toctoc.project.v1",
"project": {
"reference": "0199e3a0-0000-7000-8000-000000000101",
"name": "Parque Los Aromos",
"description": "Condominio de departamentos a pasos del metro.",
"stage": "en_verde",
"stage_label": "En verde",
"delivery_date": "2027-12-01",
"region": "Metropolitana",
"comuna": "La Florida",
"address": "Av. Vicuña Mackenna 0000",
"subsidies": [
"DS19"
],
"photos": [
"https://media.example.com/t/other/aromos-1.jpg"
],
"brochure_url": null
},
"unit_models": [
{
"reference": "0199e3a0-0000-7000-8000-000000000201",
"name": "3D2B 78 m²",
"description": null,
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"total_area_m2": 78.5,
"floor_plans": [],
"renders": [],
"tour_360_url": null,
"total_units": 24,
"available_units": 11,
"price": {
"currency": "UF",
"from": 3450,
"to": 3780
}
}
],
"extras": {
"parking_available": 8,
"storage_available": 5
}
},
"issues": [
{
"field": "project.brochure_url",
"message": "Agrega el brochure del proyecto."
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /projects/{id}/toctoc
Record where a proyecto stands on TocToc
Records draft, submitted (handed to TocToc), live or paused, and the code TocToc gave the proyecto. live needs the code (400 otherwise). Recording a code maps it to the proyecto, so the leads that carry it land on it and those already waiting on it are moved; a code that belongs to another proyecto is refused (400). Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Refused (403) to a caller whose role narrows proyectos.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X PUT https://api.vitrinadev.com/api/v1/projects/<id>/toctoc \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": "live",
"external_ref": "TT-48213"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000803",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"status": "live",
"external_ref": "TT-48213",
"notes": null,
"submitted_at": "2026-10-20T12:00:00.000Z",
"live_at": "2026-10-20T12:00:00.000Z",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /projects/{id}/whatsapp-links
Get the tracked WhatsApp links of a proyecto
One wa.me link per enabled WhatsApp number of the workspace, each prefilling a message that carries the proyecto’s whatsapp_code. A buyer who opens it and sends that message starts a conversation tied to the proyecto: the agent opens on it by name, and the lead is about it (lead.project_id, owned by the proyecto’s ejecutivos) with the link in its notes. Requires marketplace:read. A caller whose role narrows proyectos (project_visibility assigned = ejecutivo, sales_office = jefe de sala) only sees the proyectos it admits; any other answers 404, as if it did not exist. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/projects/<id>/whatsapp-links \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"whatsapp_code": "RK482",
"prefill_text": "Hola, me interesa el proyecto Parque Los Aromos (código RK482)",
"links": [
{
"messaging_account_id": "0199e3a0-0000-7000-8000-000000000501",
"name": "WhatsApp ventas",
"phone_e164": "+56912345678",
"url": "https://wa.me/56912345678?text=Hola%2C%20me%20interesa%20el%20proyecto%20Parque%20Los%20Aromos%20(c%C3%B3digo%20RK482)"
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /real-estate-offers
List the unit offers sent to old leads
Each time a unidad that matches an old lead's criteria became available, dropped in price or was released after a reserva fell through, and the workspace had the offers on, the lead was offered it; this is that ledger, newest first. A caller whose role narrows proyectos sees the offers of their proyectos only. Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
limit | query | integer | no | ≥ 1, ≤ 200 |
offset | query | integer | null | no | ≥ 0 |
curl https://api.vitrinadev.com/api/v1/real-estate-offers \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [],
"meta": {
"pagination": {
"total": 0,
"limit": 50,
"offset": 0
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /real-estate-offers/settings
Read the unit-offer settings
Whether leads that inquired hear about matching stock, how many offers one contact may get per week, and how old an inquiry may be. Off by default. Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
curl https://api.vitrinadev.com/api/v1/real-estate-offers/settings \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"enabled": false,
"weekly_cap": 1,
"max_inquiry_age_days": 365
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /real-estate-offers/settings
Change the unit-offer settings
The owner's decision to let old leads hear about matching stock (templates, STOP respected, capped per week). Only leads that inquired through Vitrina are ever offered a unidad, never portal or imported history. Turning it on starts offers for stock news from then on, with no backlog. Requires campaigns:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
curl -X PUT https://api.vitrinadev.com/api/v1/real-estate-offers/settings \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"enabled": true,
"weekly_cap": 1
}'Ejemplo de respuesta (200)
{
"data": {
"enabled": true,
"weekly_cap": 1,
"max_inquiry_age_days": 365
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /real-estate-reports/projects
Developer report per proyecto
For an inmobiliaria: per proyecto and in total, the funnel by milestone (leads that arrived in the period, how many reached each step), the stock by status, absorption and sales velocity (reservas per month, months to sell out), desistimientos by reason, and an ejecutivo ranking. Filters: project_id, sales_office_location_id (a sala de ventas), from / to. A caller whose role narrows proyectos sees only the figures of their proyectos. Only on a workspace that runs the Proyectos module; any other answers 403 MODULE_NOT_ENABLED. Requires marketplace:read.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
from | query | string | no | patrón ^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$ |
to | query | string | no | patrón ^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$ |
project_id | query | uuid | no | |
sales_office_location_id | query | uuid | no | |
pipeline_id | query | uuid | no |
curl https://api.vitrinadev.com/api/v1/real-estate-reports/projects \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"pipeline_id": "0199e3a0-0000-7000-8000-000000000301",
"period": {
"from": "2026-09-21",
"to": "2026-10-20",
"timezone": "America/Santiago"
},
"filters": {
"project_id": null,
"sales_office_id": null
},
"totals": {
"funnel": {
"cohort": 120,
"steps": [
{
"key": "lead",
"name": "Lead",
"reached": 120,
"conversion_from_previous": null
},
{
"key": "visit_scheduled",
"name": "Visita agendada",
"reached": 54,
"conversion_from_previous": 0.45
}
],
"lost": 18
},
"stock": {
"by_status": {
"disponible": 140,
"bloqueada": 2,
"reservada": 9,
"promesada": 12,
"vendida": 37,
"pausada": 0
},
"dwellings": 200,
"extras_by_status": {
"disponible": 80,
"bloqueada": 0,
"reservada": 3,
"promesada": 4,
"vendida": 13,
"pausada": 0
},
"extras": 100,
"available_value_uf": 512340.5
},
"absorption": {
"on_sale": 200,
"committed": 58,
"absorption_rate": 0.29,
"sold_rate": 0.185,
"reservations": 11,
"reservations_per_month": 11.2,
"months_to_sell_out": 12.5,
"by_month": [
{
"month": "2026-10",
"reservations": 11
}
]
},
"desistimientos": {
"total": 4,
"by_reason": [
{
"reason": "financing_rejected",
"count": 3
},
{
"reason": "price",
"count": 1
}
]
}
},
"projects": [],
"ejecutivos": []
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /reservas
List reservas
Newest first, with what has been paid. Filters: project_id, status, lead_id, cotizacion_id. Requires leads:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ reservas and negocios; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
project_id | query | uuid[] | no | |
status | query | pending \ | paid \ | expired \ |
lead_id | query | uuid | no | |
cotizacion_id | query | uuid | no | |
limit | query | integer | no | ≥ 1, ≤ 200 |
offset | query | integer | null | no | ≥ 0 |
curl https://api.vitrinadev.com/api/v1/reservas \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000a01",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"cotizacion_display_id": "CZ-12",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"co_buyer_contact_ids": [],
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"property_ids": [
"0199e3a0-0000-7000-8000-000000000401",
"0199e3a0-0000-7000-8000-000000000402"
],
"status": "pending",
"amount": 20,
"currency": "UF",
"amount_clp": 790642,
"uf_value_clp": 39532.12,
"expires_at": "2026-10-22T15:00:00.000Z",
"obligation_id": "0199e3a0-0000-7000-8000-000000000c01",
"negocio_id": null,
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T15:00:00.000Z",
"updated_at": "2026-10-20T15:00:00.000Z",
"paid_at": null,
"expired_at": null,
"cancelled_at": null,
"cancelled_reason": null,
"paid_clp": 0,
"outstanding_clp": 790642,
"payment_state": "pending",
"is_overdue": false
}
],
"meta": {
"pagination": {
"total": 1,
"limit": 50,
"offset": 0
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /reservas/{id}
Get a reserva
One reserva: the unidades it holds, the deadline, the amount, what is paid and what is left, and the negocio it opened once paid. Requires leads:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ reservas and negocios; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/reservas/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000a01",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"cotizacion_display_id": "CZ-12",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"co_buyer_contact_ids": [],
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"property_ids": [
"0199e3a0-0000-7000-8000-000000000401",
"0199e3a0-0000-7000-8000-000000000402"
],
"status": "pending",
"amount": 20,
"currency": "UF",
"amount_clp": 790642,
"uf_value_clp": 39532.12,
"expires_at": "2026-10-22T15:00:00.000Z",
"obligation_id": "0199e3a0-0000-7000-8000-000000000c01",
"negocio_id": null,
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T15:00:00.000Z",
"updated_at": "2026-10-20T15:00:00.000Z",
"paid_at": null,
"expired_at": null,
"cancelled_at": null,
"cancelled_reason": null,
"paid_clp": 0,
"outstanding_clp": 790642,
"payment_state": "pending",
"is_overdue": false
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /reservas/{id}/cancel
Release a reserva’s hold
A pending reserva only: the unidades return to disponible, the cobro is cancelled (money already paid stays on it for the business to return or apply) and the open payment link stops taking money. 409 reserva_not_pending, reserva_already_paid. Requires leads:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ reservas and negocios; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
reason | string | sí | mín. 1, máx. 500 |
curl -X POST https://api.vitrinadev.com/api/v1/reservas/<id>/cancel \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"reason": "El comprador desistió antes de pagar"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000a01",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"cotizacion_display_id": "CZ-12",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"co_buyer_contact_ids": [],
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"property_ids": [
"0199e3a0-0000-7000-8000-000000000401",
"0199e3a0-0000-7000-8000-000000000402"
],
"status": "cancelled",
"amount": 20,
"currency": "UF",
"amount_clp": 790642,
"uf_value_clp": 39532.12,
"expires_at": "2026-10-22T15:00:00.000Z",
"obligation_id": "0199e3a0-0000-7000-8000-000000000c01",
"negocio_id": null,
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T15:00:00.000Z",
"updated_at": "2026-10-20T15:00:00.000Z",
"paid_at": null,
"expired_at": null,
"cancelled_at": "2026-10-21T10:00:00.000Z",
"cancelled_reason": "El comprador desistió antes de pagar",
"paid_clp": 0,
"outstanding_clp": 0,
"payment_state": "cancelled",
"is_overdue": false
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /reservas/{id}/payment
How a reserva can be paid
For a pending reserva: the payment link (created on demand, expiring with the hold) and/or the transfer accounts, by the workspace’s charging preference. 409 reserva_not_pending otherwise. Requires leads:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. An ejecutivo only reaches their proyectos’ reservas and negocios; anything else is a 404.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/reservas/<id>/payment \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"reserva": {
"id": "0199e3a0-0000-7000-8000-000000000a01",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"project_name": "Parque Los Aromos",
"cotizacion_id": "0199e3a0-0000-7000-8000-000000000901",
"cotizacion_display_id": "CZ-12",
"lead_id": "0199e3a0-0000-7000-8000-000000000301",
"contact_id": "0199e3a0-0000-7000-8000-000000000302",
"co_buyer_contact_ids": [],
"owner_user_id": "0199e3a0-0000-7000-8000-0000000000bb",
"conversation_id": "0199e3a0-0000-7000-8000-000000000e01",
"property_ids": [
"0199e3a0-0000-7000-8000-000000000401",
"0199e3a0-0000-7000-8000-000000000402"
],
"status": "pending",
"amount": 20,
"currency": "UF",
"amount_clp": 790642,
"uf_value_clp": 39532.12,
"expires_at": "2026-10-22T15:00:00.000Z",
"obligation_id": "0199e3a0-0000-7000-8000-000000000c01",
"negocio_id": null,
"created_by": "0199e3a0-0000-7000-8000-0000000000bb",
"created_by_kind": "ui_member",
"created_at": "2026-10-20T15:00:00.000Z",
"updated_at": "2026-10-20T15:00:00.000Z",
"paid_at": null,
"expired_at": null,
"cancelled_at": null,
"cancelled_reason": null,
"paid_clp": 0,
"outstanding_clp": 790642,
"payment_state": "pending",
"is_overdue": false
},
"payment": {
"mode": "mp_first",
"link": {
"checkout_id": "0199e3a0-0000-7000-8000-000000000d01",
"checkout_url": "https://api.vitrinadev.com/p/0199e3a0-0000-7000-8000-000000000d01",
"amount_clp": 790642
},
"transfer_accounts": [
{
"alias": "Cuenta corriente",
"bank": "Banco de Chile",
"account_type": "corriente",
"account_number": "00123456789",
"holder_name": "Inmobiliaria Los Aromos SpA",
"holder_rut": "76.123.456-7"
}
]
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /toctoc-connection
The TocToc lead door of the workspace
Whether the inbound TocToc lead door exists, its last lead and the path it is served on. Requires marketplace:read. TocToc offers no API or webhook (spike #4427): its lead notifications arrive by the forwarded email at the workspace’s lead door, and publishing is assisted (export the payload, record the code TocToc returns). Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Refused (403) to a caller whose role narrows proyectos.
curl https://api.vitrinadev.com/api/v1/toctoc-connection \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"connected": true,
"connection": {
"id": "0199e3a0-0000-7000-8000-000000000802",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"token_hint": "a1b2",
"last_lead_at": "2026-10-20T12:00:00.000Z",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
},
"lead_path": "/api/v1/integrations/toctoc/leads"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /toctoc-connection/token
Create or rotate the TocToc lead door token
Creates the workspace's lead door, or rotates its token (the previous URL stops working at once). The token is returned ONCE: only its hash is kept. POST the forwarded TocToc notification to path, as JSON: either a lead (name/nombre, email/correo, phone/telefono, message/mensaje, project_code/codigo, project_name/proyecto) or the email (\{ "email": \{ "from", "subject", "text", "html", "message_id" \} \}). A body that yields no name, email or phone is kept for a person to read and creates no lead. Requires marketplace:write. TocToc offers no API or webhook (spike #4427): its lead notifications arrive by the forwarded email at the workspace’s lead door, and publishing is assisted (export the payload, record the code TocToc returns). Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Refused (403) to a caller whose role narrows proyectos.
curl -X POST https://api.vitrinadev.com/api/v1/toctoc-connection/token \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (201)
{
"data": {
"connection": {
"id": "0199e3a0-0000-7000-8000-000000000802",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"token_hint": "a1b2",
"last_lead_at": "2026-10-20T12:00:00.000Z",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
},
"token": "tt_0f3c…a1b2",
"path": "/api/v1/integrations/toctoc/leads/tt_0f3c…a1b2"
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
GET /toctoc-listings
List TocToc publications and their proyecto
The TocToc publication codes seen on leads or recorded on a proyecto, with how many leads arrived on each. mapped=false is the queue of publications waiting for a proyecto: their leads were created with no proyecto and a note. Requires marketplace:read. TocToc offers no API or webhook (spike #4427): its lead notifications arrive by the forwarded email at the workspace’s lead door, and publishing is assisted (export the payload, record the code TocToc returns). Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Refused (403) to a caller whose role narrows proyectos.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
mapped | query | true \ | false | no |
project_id | query | uuid | no | |
limit | query | integer | no | ≥ 1, ≤ 200 |
offset | query | integer | null | no | ≥ 0 |
curl https://api.vitrinadev.com/api/v1/toctoc-listings \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000801",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"external_id": "TT-48213",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"title": "Parque Los Aromos",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"lead_count": 4,
"unmapped_lead_count": 0
}
]
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /toctoc-listings
Map a TocToc publication code to a proyecto
Maps the code TocToc gave a publication to a proyecto ahead of its first lead. Idempotent on the code: posting an already-seen one re-maps it, stamps the proyecto on its waiting leads and routes the unowned ones to the proyecto's ejecutivos. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Refused (403) to a caller whose role narrows proyectos.
curl -X POST https://api.vitrinadev.com/api/v1/toctoc-listings \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"external_id": "TT-48213"
}'Ejemplo de respuesta (201)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000801",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"external_id": "TT-48213",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"title": "Parque Los Aromos",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"leads_mapped": 0
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /toctoc-listings/{id}
Map or unmap a TocToc publication
Sets the proyecto of a publication (project_id), or clears it with null. Mapping stamps the proyecto on the leads waiting on the publication and routes the unowned ones to its ejecutivos; unmapping only affects leads that arrive afterwards. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED. Refused (403) to a caller whose role narrows proyectos.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X PATCH https://api.vitrinadev.com/api/v1/toctoc-listings/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_id": "0199e3a0-0000-7000-8000-000000000101"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000801",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"external_id": "TT-48213",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"title": "Parque Los Aromos",
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"leads_mapped": 3
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /unit-models
List tipologías
Live tipologías of live proyectos, grouped by proyecto (newest first) then by name. Filters ANDed: project_id, the proyecto’s comuna and stage (etapa), min_bedrooms, min_bathrooms, free text q. Each row names its proyecto. Requires marketplace:read. A caller whose role narrows proyectos (project_visibility assigned = ejecutivo, sales_office = jefe de sala) only sees the proyectos it admits; any other answers 404, as if it did not exist. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
project_id | query | uuid[] | no | |
comuna | query | string[] | no | |
stage | query | en_blanco \ | en_verde \ | entrega_inmediata[] |
min_bedrooms | query | integer | null | no | ≥ 0, ≤ 99 |
min_bathrooms | query | integer | null | no | ≥ 0, ≤ 99 |
q | query | string | no | máx. 200 |
limit | query | integer | no | ≥ 1, ≤ 200 |
offset | query | integer | null | no | ≥ 0 |
curl https://api.vitrinadev.com/api/v1/unit-models \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000201",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"name": "3D2B 78 m²",
"description": "Esquina, con terraza en L.",
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"total_area_m2": 78.5,
"floor_plans": [
"https://media.example.com/t/other/planta-3d2b.pdf"
],
"renders": [
"https://media.example.com/t/other/render-3d2b.jpg"
],
"tour_360_url": "https://tour.example.com/3d2b",
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Parque Los Aromos",
"comuna": "La Florida",
"stage": "en_verde"
}
}
],
"meta": {
"pagination": {
"total": 1,
"limit": 50,
"offset": 0
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /unit-models
Add a tipología to a proyecto
Names are unique among the proyecto’s live tipologías (409 otherwise). floor_plans (plantas), renders and tour_360_url are public URLs: upload files with POST /tenant/media first. Requires marketplace:write. A caller whose role narrows proyectos (project_visibility assigned = ejecutivo, sales_office = jefe de sala) only sees the proyectos it admits; any other answers 404, as if it did not exist. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
curl -X POST https://api.vitrinadev.com/api/v1/unit-models \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"name": "3D2B 78 m²",
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"total_area_m2": 78.5
}'Ejemplo de respuesta (201)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000201",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"name": "3D2B 78 m²",
"description": "Esquina, con terraza en L.",
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"total_area_m2": 78.5,
"floor_plans": [
"https://media.example.com/t/other/planta-3d2b.pdf"
],
"renders": [
"https://media.example.com/t/other/render-3d2b.jpg"
],
"tour_360_url": "https://tour.example.com/3d2b",
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /unit-models/{id}
Remove a tipología
Requires marketplace:write. A caller whose role narrows proyectos (project_visibility assigned = ejecutivo, sales_office = jefe de sala) only sees the proyectos it admits; any other answers 404, as if it did not exist. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X DELETE https://api.vitrinadev.com/api/v1/unit-models/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000201",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"name": "3D2B 78 m²",
"deleted": true
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /unit-models/{id}
One tipología
Requires marketplace:read. A caller whose role narrows proyectos (project_visibility assigned = ejecutivo, sales_office = jefe de sala) only sees the proyectos it admits; any other answers 404, as if it did not exist. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/unit-models/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000201",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"name": "3D2B 78 m²",
"description": "Esquina, con terraza en L.",
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"total_area_m2": 78.5,
"floor_plans": [
"https://media.example.com/t/other/planta-3d2b.pdf"
],
"renders": [
"https://media.example.com/t/other/render-3d2b.jpg"
],
"tour_360_url": "https://tour.example.com/3d2b",
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /unit-models/{id}
Edit a tipología
Partial update; null clears a field. A tipología stays in its proyecto. Requires marketplace:write. A caller whose role narrows proyectos (project_visibility assigned = ejecutivo, sales_office = jefe de sala) only sees the proyectos it admits; any other answers 404, as if it did not exist. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X PATCH https://api.vitrinadev.com/api/v1/unit-models/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"bedrooms": 3
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000201",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"name": "3D2B 78 m²",
"description": "Esquina, con terraza en L.",
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"total_area_m2": 78.5,
"floor_plans": [
"https://media.example.com/t/other/planta-3d2b.pdf"
],
"renders": [
"https://media.example.com/t/other/render-3d2b.jpg"
],
"tour_360_url": "https://tour.example.com/3d2b",
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /units
List unidades (a proyecto’s stock)
Live unidades of live proyectos, by floor, then kind, then number in natural order. Filters ANDed: project_id, unit_model_id, kind, status, min_floor / max_floor, min_bedrooms, free text q. meta.status_counts counts the same filters WITHOUT status, for a grid’s status chips. A unidad is a property row: GET /properties lists unidades too with include_units=true. Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
project_id | query | uuid[] | no | |
unit_model_id | query | uuid[] | no | |
kind | query | departamento \ | casa \ | estacionamiento \ |
status | query | disponible \ | bloqueada \ | reservada \ |
min_floor | query | integer | null | no | ≥ -10, ≤ 300 |
max_floor | query | integer | null | no | ≥ -10, ≤ 300 |
min_bedrooms | query | integer | null | no | ≥ 0, ≤ 99 |
q | query | string | no | máx. 200 |
limit | query | integer | no | ≥ 1, ≤ 500 |
offset | query | integer | null | no | ≥ 0 |
curl https://api.vitrinadev.com/api/v1/units \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"id": "0199e3a0-0000-7000-8000-000000000401",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"display_id": "I-42",
"title": "Departamento 1203 · Parque Los Aromos",
"description": null,
"operation": "venta",
"property_type": "departamento",
"kind": "departamento",
"status": "disponible",
"region": "Metropolitana",
"comuna": "La Florida",
"sector": null,
"address": null,
"sale_price_amount": 3250.5,
"sale_price_currency": "UF",
"rent_price_amount": null,
"rent_price_currency": null,
"common_expenses_clp": null,
"property_tax_clp": null,
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"total_area_m2": 78.5,
"parking_spaces": null,
"storage_units": null,
"orientation": "nororiente",
"floor": 12,
"year_built": null,
"furnished": null,
"pets_allowed": null,
"photos": [],
"broker_user_id": null,
"owner_name": null,
"owner_phone": null,
"owner_email": null,
"source": "import",
"external_ref": null,
"protected_fields": [],
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"unit_model_id": "0199e3a0-0000-7000-8000-000000000201",
"unit_number": "1203",
"hold_expires_at": null,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"sale_price": {
"amount": 3250.5,
"currency": "UF",
"amount_clp": 128500000,
"amount_uf": 3250.5
},
"rent_price": null,
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Parque Los Aromos"
},
"unit_model": {
"id": "0199e3a0-0000-7000-8000-000000000201",
"name": "3D2B 78 m²"
}
}
],
"meta": {
"pagination": {
"total": 1,
"limit": 100,
"offset": 0
},
"status_counts": {
"disponible": 1
},
"uf_value": {
"clp": 39532.12,
"date": "2026-10-20"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /units
Add a unidad by hand
A departamento, casa, estacionamiento or bodega of a proyecto; estacionamientos and bodegas are unidades of their own, priced and sold alone or with a departamento. The number is unique per proyecto and kind (409 otherwise); the tipología must be one of the proyecto’s. Born disponible. A unidad’s status is its negocio’s: by hand it can only be paused and put back (disponible ⇄ pausada), and no import ever writes it. Once the proyecto has a published lista de precios (/price-lists), its unidades’ prices change only by publishing a new version: a price here answers 409 unit_price_owned_by_price_list. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
curl -X POST https://api.vitrinadev.com/api/v1/units \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"kind": "estacionamiento",
"unit_number": "E-12",
"floor": -1,
"sale_price_amount": 250,
"sale_price_currency": "UF"
}'Ejemplo de respuesta (201)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000401",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"display_id": "I-42",
"title": "Departamento 1203 · Parque Los Aromos",
"description": null,
"operation": "venta",
"property_type": "departamento",
"kind": "departamento",
"status": "disponible",
"region": "Metropolitana",
"comuna": "La Florida",
"sector": null,
"address": null,
"sale_price_amount": 3250.5,
"sale_price_currency": "UF",
"rent_price_amount": null,
"rent_price_currency": null,
"common_expenses_clp": null,
"property_tax_clp": null,
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"total_area_m2": 78.5,
"parking_spaces": null,
"storage_units": null,
"orientation": "nororiente",
"floor": 12,
"year_built": null,
"furnished": null,
"pets_allowed": null,
"photos": [],
"broker_user_id": null,
"owner_name": null,
"owner_phone": null,
"owner_email": null,
"source": "import",
"external_ref": null,
"protected_fields": [],
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"unit_model_id": "0199e3a0-0000-7000-8000-000000000201",
"unit_number": "1203",
"hold_expires_at": null,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"sale_price": {
"amount": 3250.5,
"currency": "UF",
"amount_clp": 128500000,
"amount_uf": 3250.5
},
"rent_price": null,
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Parque Los Aromos"
},
"unit_model": {
"id": "0199e3a0-0000-7000-8000-000000000201",
"name": "3D2B 78 m²"
}
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /units/{id}
Remove a unidad
Takes it out of the stock. A unidad a negocio holds (bloqueada, reservada, promesada, vendida) cannot be removed (409 unit_held_by_negocio). Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | mín. 1, máx. 64 |
curl -X DELETE https://api.vitrinadev.com/api/v1/units/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000401",
"display_id": "I-42",
"unit_number": "1203",
"deleted": true
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /units/{id}
One unidad
By uuid or display id (I-42). Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | mín. 1, máx. 64 |
curl https://api.vitrinadev.com/api/v1/units/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000401",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"display_id": "I-42",
"title": "Departamento 1203 · Parque Los Aromos",
"description": null,
"operation": "venta",
"property_type": "departamento",
"kind": "departamento",
"status": "disponible",
"region": "Metropolitana",
"comuna": "La Florida",
"sector": null,
"address": null,
"sale_price_amount": 3250.5,
"sale_price_currency": "UF",
"rent_price_amount": null,
"rent_price_currency": null,
"common_expenses_clp": null,
"property_tax_clp": null,
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"total_area_m2": 78.5,
"parking_spaces": null,
"storage_units": null,
"orientation": "nororiente",
"floor": 12,
"year_built": null,
"furnished": null,
"pets_allowed": null,
"photos": [],
"broker_user_id": null,
"owner_name": null,
"owner_phone": null,
"owner_email": null,
"source": "import",
"external_ref": null,
"protected_fields": [],
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"unit_model_id": "0199e3a0-0000-7000-8000-000000000201",
"unit_number": "1203",
"hold_expires_at": null,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"sale_price": {
"amount": 3250.5,
"currency": "UF",
"amount_clp": 128500000,
"amount_uf": 3250.5
},
"rent_price": null,
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Parque Los Aromos"
},
"unit_model": {
"id": "0199e3a0-0000-7000-8000-000000000201",
"name": "3D2B 78 m²"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /units/{id}
Edit a unidad
Partial update; null clears a field. The proyecto is fixed. A field edited by hand on an imported unidad is protected from the next import (release it with POST /units/\{id\}/release-fields). A unidad’s status is its negocio’s: by hand it can only be paused and put back (disponible ⇄ pausada), and no import ever writes it. A status change while a negocio holds the unidad is a 409 unit_status_owned_by_negocio. Once the proyecto has a published lista de precios (/price-lists), its unidades’ prices change only by publishing a new version: a price here answers 409 unit_price_owned_by_price_list. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | mín. 1, máx. 64 |
curl -X PATCH https://api.vitrinadev.com/api/v1/units/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": "pausada"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000401",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"display_id": "I-42",
"title": "Departamento 1203 · Parque Los Aromos",
"description": null,
"operation": "venta",
"property_type": "departamento",
"kind": "departamento",
"status": "disponible",
"region": "Metropolitana",
"comuna": "La Florida",
"sector": null,
"address": null,
"sale_price_amount": 3250.5,
"sale_price_currency": "UF",
"rent_price_amount": null,
"rent_price_currency": null,
"common_expenses_clp": null,
"property_tax_clp": null,
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"total_area_m2": 78.5,
"parking_spaces": null,
"storage_units": null,
"orientation": "nororiente",
"floor": 12,
"year_built": null,
"furnished": null,
"pets_allowed": null,
"photos": [],
"broker_user_id": null,
"owner_name": null,
"owner_phone": null,
"owner_email": null,
"source": "import",
"external_ref": null,
"protected_fields": [],
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"unit_model_id": "0199e3a0-0000-7000-8000-000000000201",
"unit_number": "1203",
"hold_expires_at": null,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"sale_price": {
"amount": 3250.5,
"currency": "UF",
"amount_clp": 128500000,
"amount_uf": 3250.5
},
"rent_price": null,
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Parque Los Aromos"
},
"unit_model": {
"id": "0199e3a0-0000-7000-8000-000000000201",
"name": "3D2B 78 m²"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /units/{id}/price-history
A unidad’s price in every published lista de precios
Newest version first: the price in UF and in CLP with the day’s UF (meta.uf_value), who set and who published it, and when. Requires marketplace:read. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | mín. 1, máx. 64 |
curl https://api.vitrinadev.com/api/v1/units/<id>/price-history \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": [
{
"price_list_version_id": "0199e3a0-0000-7000-8000-000000000501",
"version_number": 2,
"name": "Lista noviembre 2026",
"is_current": true,
"published_at": "2026-10-20T12:30:00.000Z",
"published_by": "0199e3a0-0000-7000-8000-0000000000bb",
"published_by_kind": "ui_member",
"superseded_at": null,
"price_uf": 3310,
"price_clp": 130851317,
"set_by": "0199e3a0-0000-7000-8000-0000000000bb",
"set_by_kind": "ui_member",
"set_at": "2026-10-20T12:10:00.000Z"
}
],
"meta": {
"uf_value": {
"clp": 39532.12,
"date": "2026-10-20"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /units/{id}/release-fields
Let a unidad’s protected fields follow the import again
Removes fields from protected_fields, so the next import may overwrite them. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | string | sí | mín. 1, máx. 64 |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
fields | string[] | sí |
curl -X POST https://api.vitrinadev.com/api/v1/units/<id>/release-fields \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"fields": [
"sale_price_amount"
]
}'Ejemplo de respuesta (200)
{
"data": {
"id": "0199e3a0-0000-7000-8000-000000000401",
"tenant_id": "0199e3a0-0000-7000-8000-0000000000aa",
"display_id": "I-42",
"title": "Departamento 1203 · Parque Los Aromos",
"description": null,
"operation": "venta",
"property_type": "departamento",
"kind": "departamento",
"status": "disponible",
"region": "Metropolitana",
"comuna": "La Florida",
"sector": null,
"address": null,
"sale_price_amount": 3250.5,
"sale_price_currency": "UF",
"rent_price_amount": null,
"rent_price_currency": null,
"common_expenses_clp": null,
"property_tax_clp": null,
"bedrooms": 3,
"bathrooms": 2,
"usable_area_m2": 72.5,
"terrace_area_m2": 6,
"total_area_m2": 78.5,
"parking_spaces": null,
"storage_units": null,
"orientation": "nororiente",
"floor": 12,
"year_built": null,
"furnished": null,
"pets_allowed": null,
"photos": [],
"broker_user_id": null,
"owner_name": null,
"owner_phone": null,
"owner_email": null,
"source": "import",
"external_ref": null,
"protected_fields": [],
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"unit_model_id": "0199e3a0-0000-7000-8000-000000000201",
"unit_number": "1203",
"hold_expires_at": null,
"created_by": null,
"created_at": "2026-10-20T12:00:00.000Z",
"updated_at": "2026-10-20T12:00:00.000Z",
"sale_price": {
"amount": 3250.5,
"currency": "UF",
"amount_clp": 128500000,
"amount_uf": 3250.5
},
"rent_price": null,
"project": {
"id": "0199e3a0-0000-7000-8000-000000000101",
"name": "Parque Los Aromos"
},
"unit_model": {
"id": "0199e3a0-0000-7000-8000-000000000201",
"name": "3D2B 78 m²"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /units/import
Import steps 2–3: dry run, then load a proyecto’s unidades
Loads a proyecto’s stock from the inmobiliaria’s Excel or CSV (multipart: file, project_id, mapping as JSON text, dry_run, default_kind) or from JSON rows (one object per unidad keyed by column name — the MCP path). dry_run defaults to true: the report says, row by row, what would be created, updated (which fields) or left unchanged, and every error with its field; nothing is written. Send dry_run: false to write every row without an error in ONE transaction. A unidad is matched by proyecto + kind + number, so re-importing a file changes nothing and an updated file updates in place; unidades missing from the file are counted (not_in_file), never removed. An import never writes a unidad’s status (there is no status field; a column like «Estado» is listed in ignored_status_columns), and fields a person edited by hand stay (protected_skipped). A tipología is named by its name in the proyecto; its dormitorios, baños and m² fill a new unidad’s when the file leaves them empty. Once the proyecto has a published lista de precios, the price column is left out (ignored_price_column): prices then come from the list only. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
curl -X POST https://api.vitrinadev.com/api/v1/units/import \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"rows": [
{
"Número": "1203",
"Tipo": "Depto",
"Tipología": "3D2B",
"Piso": 12,
"Precio UF": "3.250,5"
},
{
"Número": "E-12",
"Tipo": "Estacionamiento",
"Piso": -1,
"Precio UF": 250
}
],
"mapping": {
"unit_number": "Número",
"kind": "Tipo",
"unit_model": "Tipología",
"floor": "Piso",
"price_uf": "Precio UF"
},
"dry_run": true
}'Ejemplo de respuesta (200)
{
"data": {
"dry_run": true,
"project_id": "0199e3a0-0000-7000-8000-000000000101",
"mapping": {
"unit_number": "Número",
"kind": "Tipo",
"unit_model": "Tipología",
"floor": "Piso",
"price_uf": "Precio UF"
},
"ignored_status_columns": [
"Estado"
],
"ignored_price_column": null,
"summary": {
"total_rows": 3,
"create": 1,
"update": 1,
"unchanged": 0,
"error": 1,
"not_in_file": 0
},
"rows": [
{
"row_number": 2,
"action": "create",
"unit_number": "1203",
"kind": "departamento",
"unit_id": null,
"display_id": null,
"fields": [
"floor",
"sale_price_amount",
"sale_price_currency",
"unit_model_id"
],
"protected_skipped": [],
"status": "disponible",
"errors": []
},
{
"row_number": 3,
"action": "update",
"unit_number": "E-12",
"kind": "estacionamiento",
"unit_id": "0199e3a0-0000-7000-8000-000000000401",
"display_id": "I-43",
"fields": [
"sale_price_amount"
],
"protected_skipped": [],
"status": "reservada",
"errors": []
},
{
"row_number": 4,
"action": "error",
"unit_number": "1204",
"kind": "departamento",
"unit_id": null,
"display_id": null,
"fields": [],
"protected_skipped": [],
"status": "disponible",
"errors": [
{
"field": "unit_model",
"message": "La tipología «4D3B» no existe en este proyecto. Créala primero o corrige el nombre."
}
]
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /units/import/columns
Import step 1: read a stock file’s columns
Multipart, the file in a part named file (.xlsx, .xls or .csv, up to 20 MB; the first sheet with data, the first non-empty row is the header). Returns the header, the first rows, the mapping we suggest from the column names and every field a column can feed — the mapping screen. Writes and stores nothing: send the same file to POST /units/import. Requires marketplace:write. Only on a workspace that runs the Proyectos module (real-estate vertical, inmobiliaria); any other answers 403 MODULE_NOT_ENABLED.
curl -X POST https://api.vitrinadev.com/api/v1/units/import/columns \
-H "Authorization: Bearer $VITRINA_KEY" \
-F "file=@/path/to/file.png"Ejemplo de respuesta (200)
{
"data": {
"format": "xlsx",
"sheet_name": "Stock",
"header": [
"Número",
"Tipo",
"Tipología",
"Piso",
"Precio UF",
"Estado"
],
"row_count": 200,
"sample": [
[
"1203",
"Depto",
"3D2B",
"12",
"3.250,5",
"Disponible"
]
],
"suggested_mapping": {
"unit_number": "Número",
"kind": "Tipo",
"unit_model": "Tipología",
"floor": "Piso",
"price_uf": "Precio UF"
},
"ignored_status_columns": [
"Estado"
],
"fields": [
{
"key": "unit_number",
"label": "Número de unidad",
"required": true,
"description": "The unidad’s number as the inmobiliaria writes it."
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429