VitrinaAPI

Vender una unidad

Los documentos con que una automotora cotiza, reserva y vende.

AutomotorasSolo en los workspaces de automotoras.

POST /quotes emite una cotización y le asigna su folio. POST /reservations bloquea la unidad. POST /sale-notes la vende, y el auto pasa a vendido cuando alguien aprueba esa nota.

Ninguno de los nueve recursos de abajo se edita libremente. Cada uno acepta un conjunto corto de verbos. Anular deja el folio y la razón en el documento; corregir es anular y volver a emitir.

RecursoScopeQué es
Publicacionesmarketplace:read / marketplace:writeEl estado del auto en cada portal conectado.
Cotizacionesquotes:read / quotes:write / quotes:voidUna oferta de precio congelada. No reserva nada.
Reservasreservations:read / reservations:write / reservations:void / reservations:dispose_abonoUn cupo bloqueado sobre una unidad, con abono opcional.
Notas de ventasale_notes:read / sale_notes:write / sale_notes:voidEl documento que vende el auto.
Notas de comprapurchase_notes:read / purchase_notes:write / purchase_notes:voidEl documento que le da costo a un auto que entra.
Pagos de documentosdocument_payments:read / document_payments:writeDinero contra una reserva o una nota de venta.
Consignacionesconsignments:read / consignments:writeEl contrato bajo el cual se vende el auto de otra persona.
Solicitudes de créditocredit_applications:read / credit_applications:writeEl expediente que persigue una carpeta bancaria.
Aprobaciones de precioprice_approval:read / price_approval:request / price_approval:approveLa autoridad sobre un precio bajo el de referencia.

Todos estos POST aceptan Idempotency-Key. Repetir la llamada con el mismo valor devuelve el documento ya emitido y no consume otro folio. Los códigos que puedes recibir están en Errores.

Las respuestas de esta página salen de una corrida contra un workspace de prueba. Los identificadores serán otros; la forma es la misma.

Publicar en portales

curl -X POST https://api.vitrinadev.com/api/v1/vehicles/de7d959a-292f-4491-92ce-2028fa9114f0/publish \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "integration_ids": ["e6038419-209e-42e2-80ed-2a8451156a8a"] }'

integration_ids nombra los portales a los que quieres publicar. La respuesta trae un veredicto por integración, así que un 200 todavía no significa que el aviso esté arriba:

{
  "data": [
    {
      "integration_id": "e6038419-209e-42e2-80ed-2a8451156a8a",
      "provider": "facebook_marketplace",
      "status": "pending",
      "external_id": "fbm-task:b802ddef-cf01-41e6-9072-2f571c06acfc",
      "publication": {
        "id": "aed50dde-d45b-47f2-9564-fdcb296b14f3",
        "tenant_id": "00000000-0000-4000-8000-000000000001",
        "vehicle_id": "de7d959a-292f-4491-92ce-2028fa9114f0",
        "marketplace_account_id": "e6038419-209e-42e2-80ed-2a8451156a8a",
        "provider": "facebook_marketplace",
        "external_id": "fbm-task:b802ddef-cf01-41e6-9072-2f571c06acfc",
        "status": "pending",
        "origin": "vitrina",
        "permalink": null,
        "last_synced_at": null,
        "last_published_at": "2026-09-23T01:28:12.731Z",
        "last_error": null,
        "close_retry_count": 0,
        "portal_state": null,
        "portal_state_at": null,
        "raw_provider_payload": {
          "taskId": "b802ddef-cf01-41e6-9072-2f571c06acfc"
        },
        "created_at": "2026-09-23T01:28:12.743Z",
        "updated_at": "2026-09-23T01:28:12.743Z"
      }
    }
  ]
}

Trampa

Facebook Marketplace responde pending porque no hay aviso todavía

La publicación la completa la extensión de Vitrina en el navegador de un vendedor, a su propio ritmo. Por eso external_id es un identificador provisorio (fbm-task:…) y permalink viene en null. Si la extensión está apagada o en pausa, la publicación no avanza. El resultado real llega por GET /vehicles/{id}/publications o por los eventos de más abajo.

DELETE /vehicles/{id}/publications/{pubId} retira una publicación puntual y POST /vehicles/{id}/close-ads cierra todas las de un auto. La fila nunca desaparece: queda con el estado terminal del portal, así que «¿qué pasó con esa publicación?» siempre tiene respuesta.

{
  "data": {
    "id": "aed50dde-d45b-47f2-9564-fdcb296b14f3",
    "tenant_id": "00000000-0000-4000-8000-000000000001",
    "vehicle_id": "de7d959a-292f-4491-92ce-2028fa9114f0",
    "marketplace_account_id": "e6038419-209e-42e2-80ed-2a8451156a8a",
    "provider": "facebook_marketplace",
    "external_id": "fbm-task:b802ddef-cf01-41e6-9072-2f571c06acfc",
    "status": "removing",
    "origin": "vitrina",
    "permalink": null,
    "last_synced_at": null,
    "last_published_at": "2026-09-23T01:28:12.731Z",
    "last_error": null,
    "close_retry_count": 0,
    "portal_state": null,
    "portal_state_at": null,
    "raw_provider_payload": {
      "taskId": "b802ddef-cf01-41e6-9072-2f571c06acfc"
    },
    "created_at": "2026-09-23T01:28:12.743Z",
    "updated_at": "2026-09-23T01:28:22.295Z"
  }
}

Cotizar

curl -X POST https://api.vitrinadev.com/api/v1/quotes \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "vehicle_id": "de7d959a-292f-4491-92ce-2028fa9114f0",
    "buyer_contact_id": "01a0cbdd-304a-70d8-951f-5e4b481301c9",
    "offered_price_clp": 8990000,
    "tax_treatment": "afecto",
    "expires_on": "2026-09-30"
  }'
{
  "data": {
    "id": "982dd531-6b1a-49f1-a947-f8520e7bb648",
    "tenant_id": "00000000-0000-4000-8000-000000000001",
    "display_id": "Q-7",
    "display_seq": 7,
    "vehicle_id": "de7d959a-292f-4491-92ce-2028fa9114f0",
    "buyer_contact_id": "01a0cbdd-304a-70d8-951f-5e4b481301c9",
    "salesperson_id": null,
    "list_price_clp": 8990000,
    "offered_price_clp": 8990000,
    "tax_treatment": "afecto",
    "discount_pct": 0,
    "unit_make": "Peugeot",
    "unit_model": "208",
    "unit_version": "Active 1.2",
    "unit_year": 2021,
    "unit_plate": "KXPW34",
    "unit_vin": "VF3CCHMZ6MT012345",
    "unit_odometer_value": 38200,
    "unit_odometer_unit": "KM",
    "unit_color": "Gris",
    "discount_hidden": false,
    "issued_at": "2026-09-23T01:24:47.318Z",
    "expires_on": "2026-09-30",
    "state": "vigente",
    "voided_at": null,
    "void_reason": null,
    "voided_by": null,
    "extended_at": null,
    "extend_reason": null,
    "extended_by": null,
    "archived_at": null,
    "archive_reason": null,
    "archived_by": null,
    "created_at": "2026-09-23T01:24:47.318Z",
    "updated_at": "2026-09-23T01:24:47.318Z"
  }
}

Los campos unit_* son la identidad del auto congelada al emitir: marca, modelo, versión, año, patente, VIN, kilometraje y color. Repreciar o corregir el auto después no cambia ninguna cotización ya emitida, y por eso esos campos tampoco son parámetros de entrada.

El folio Q-7 sirve en cualquier ruta que acepte {id}. state es derivado (vigente, expirada o nula) y una cotización sigue vigente durante todo el día de expires_on.

Un documento emitido acepta exactamente tres cambios: POST /quotes/{id}/void, POST /quotes/{id}/extend y POST /quotes/{id}/archive. Los tres piden un void_reason, extend_reason o archive_reason visible. Ninguno toma el actor del body: voided_by queda con el principal autenticado.

Trampa

Una cotización nula no se puede volver a anular

Un segundo void es 409 y el primer actor y la primera razón quedan como están. Para corregir, emite otra cotización.

{
  "error": {
    "code": "CONFLICT",
    "message": "Quote Q-8 is already voided; a void cannot be restated.",
    "requestId": "8a40a45a-975d-4fa4-a685-a40deabe4c6e"
  }
}

Reservar

La reserva es el único documento que bloquea la unidad. Varios clientes pueden tener cotizaciones vigentes sobre el mismo auto; solo una reserva puede estar activa.

curl -X POST https://api.vitrinadev.com/api/v1/reservations \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "vehicle_id": "81e56530-5365-4e4c-a423-2bb043798527",
    "holder_contact_id": "01a0cbdd-305f-7312-9345-5818a81e1fd8",
    "agreed_price_clp": 10490000,
    "hold_expires_on": "2026-09-30"
  }'
{
  "data": {
    "id": "55923d26-8109-4d13-85aa-8ae2b9b10454",
    "tenant_id": "00000000-0000-4000-8000-000000000001",
    "display_id": "R-5",
    "display_seq": 5,
    "vehicle_id": "81e56530-5365-4e4c-a423-2bb043798527",
    "holder_contact_id": "01a0cbdd-305f-7312-9345-5818a81e1fd8",
    "salesperson_id": null,
    "agreed_price_clp": 10490000,
    "abono_expected_clp": 300000,
    "taken_at": "2026-09-23T01:25:07.880Z",
    "hold_expires_on": "2026-09-30",
    "keep_advertised": true,
    "status": "activa",
    "abono_disposition": null,
    "abono_disposition_reason": null,
    "abono_disposition_at": null,
    "abono_disposition_by": null,
    "voided_at": null,
    "void_reason": null,
    "voided_by": null,
    "created_at": "2026-09-23T01:25:07.880Z",
    "updated_at": "2026-09-23T01:25:07.880Z"
  }
}

hold_expires_on es obligatorio y no tiene default. Una reserva bloquea inventario y puede tomar un abono no reembolsable, así que cada una declara su propio plazo. Si omites agreed_price_clp, se copia el precio de publicación vigente del auto. keep_advertised decide si los avisos siguen activos mientras dura el cupo.

Cerrar una reserva con pagos encima obliga a decir qué pasó con el dinero. La ruta es POST /reservations/{id}/abono-disposition, el destino es aplicado, devuelto o perdido, y la misma llamada pide el void_reason porque cierra el cupo:

{
  "data": {
    "id": "96b5d519-20af-4afb-9d85-d1c5d1134fa6",
    "tenant_id": "00000000-0000-4000-8000-000000000001",
    "display_id": "R-6",
    "display_seq": 6,
    "vehicle_id": "c9309769-a5d0-4ec3-a72b-c38463df3bf7",
    "holder_contact_id": "01a0cbdd-304a-70d8-951f-5e4b481301c9",
    "salesperson_id": null,
    "agreed_price_clp": 11290000,
    "abono_expected_clp": 300000,
    "taken_at": "2026-09-23T01:28:50.056Z",
    "hold_expires_on": "2026-09-30",
    "keep_advertised": false,
    "status": "anulada",
    "abono_disposition": "perdido",
    "abono_disposition_reason": "Abono no reembolsable según el contrato firmado",
    "abono_disposition_at": "2026-09-23T01:29:11.554Z",
    "abono_disposition_by": "0eb8e217-8a6f-4cb8-8216-b077194b3df7",
    "voided_at": "2026-09-23T01:29:11.554Z",
    "void_reason": "El comprador no volvió",
    "voided_by": "0eb8e217-8a6f-4cb8-8216-b077194b3df7",
    "created_at": "2026-09-23T01:28:50.056Z",
    "updated_at": "2026-09-23T01:29:11.554Z"
  }
}

POST /reservations/{id}/convert produce una nota de venta nueva, hereda el auto y el comprador, y arrastra los pagos al documento resultante. El precio viene de agreed_price_clp y no es un parámetro de esta ruta.

{
  "data": {
    "reservation": {
      "id": "55923d26-8109-4d13-85aa-8ae2b9b10454",
      "tenant_id": "00000000-0000-4000-8000-000000000001",
      "display_id": "R-5",
      "display_seq": 5,
      "vehicle_id": "81e56530-5365-4e4c-a423-2bb043798527",
      "holder_contact_id": "01a0cbdd-305f-7312-9345-5818a81e1fd8",
      "salesperson_id": null,
      "agreed_price_clp": 10490000,
      "abono_expected_clp": 300000,
      "taken_at": "2026-09-23T01:25:07.880Z",
      "hold_expires_on": "2026-09-30",
      "keep_advertised": true,
      "status": "completada",
      "abono_disposition": "aplicado",
      "abono_disposition_reason": "Abono aplicado a la nota de venta V-2 (BR-237): la reserva R-5 se completó con la venta y el dinero recibido se acreditó en el documento resultante, copiado pago por pago (BR-291).",
      "abono_disposition_at": "2026-09-23T01:25:24.288Z",
      "abono_disposition_by": "0eb8e217-8a6f-4cb8-8216-b077194b3df7",
      "voided_at": null,
      "void_reason": null,
      "voided_by": null,
      "created_at": "2026-09-23T01:25:07.880Z",
      "updated_at": "2026-09-23T01:25:24.242Z"
    },
    "sale_note": {
      "id": "32e4f73b-1b37-407a-9442-0c110cd68d08",
      "tenant_id": "00000000-0000-4000-8000-000000000001",
      "display_id": "V-2",
      "display_seq": 2,
      "vehicle_id": "81e56530-5365-4e4c-a423-2bb043798527",
      "buyer_contact_id": "01a0cbdd-305f-7312-9345-5818a81e1fd8",
      "lead_id": null,
      "converted_from_reservation_id": "55923d26-8109-4d13-85aa-8ae2b9b10454",
      "seller_of_record": "automotora",
      "salesperson_id": null,
      "net_clp": 10490000,
      "tax_clp": null,
      "tax_treatment": "afecto",
      "status": "issued",
      "issued_at": "2026-09-23T01:25:24.242Z",
      "approved_by": null,
      "approved_at": null,
      "voided_at": null,
      "void_reason": null,
      "voided_by": null,
      "created_at": "2026-09-23T01:25:24.242Z",
      "updated_at": "2026-09-23T01:25:24.242Z"
    },
    "carried_payments": [
      {
        "id": "01a0cbde-13ff-7fba-bc54-a0b8b687bcf1",
        "tenant_id": "00000000-0000-4000-8000-000000000001",
        "reservation_id": null,
        "sale_note_id": "32e4f73b-1b37-407a-9442-0c110cd68d08",
        "carried_from_reservation_id": "55923d26-8109-4d13-85aa-8ae2b9b10454",
        "instrument": "transferencia",
        "amount_clp": 300000,
        "paid_on": "2026-09-23",
        "bank": "Banco de Chile",
        "account_number": null,
        "document_number": "8842190",
        "note": null,
        "card_fee_bps": null,
        "card_surcharge_clp": null,
        "card_surcharge_source": null,
        "created_at": "2026-09-23T01:25:24.095Z",
        "updated_at": "2026-09-23T01:25:24.174Z"
      }
    ]
  }
}

Vender

curl -X POST https://api.vitrinadev.com/api/v1/sale-notes \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "vehicle_id": "de7d959a-292f-4491-92ce-2028fa9114f0",
    "buyer_contact_id": "01a0cbdd-304a-70d8-951f-5e4b481301c9",
    "seller_of_record": "automotora",
    "net_clp": 8990000,
    "tax_clp": 1708100,
    "tax_treatment": "afecto"
  }'

Emitir asigna el folio y deja la nota en issued. La venta se cierra con POST /sale-notes/{id}/approve:

{
  "data": {
    "id": "486de281-2d4a-4e0c-a98c-95617e1b4093",
    "tenant_id": "00000000-0000-4000-8000-000000000001",
    "display_id": "V-4",
    "display_seq": 4,
    "vehicle_id": "de7d959a-292f-4491-92ce-2028fa9114f0",
    "buyer_contact_id": "01a0cbdd-304a-70d8-951f-5e4b481301c9",
    "lead_id": null,
    "converted_from_reservation_id": null,
    "seller_of_record": "automotora",
    "salesperson_id": null,
    "net_clp": 8990000,
    "tax_clp": 1708100,
    "tax_treatment": "afecto",
    "status": "approved",
    "issued_at": "2026-09-23T01:34:49.722Z",
    "approved_by": "0eb8e217-8a6f-4cb8-8216-b077194b3df7",
    "approved_at": "2026-09-23T01:34:51.127Z",
    "voided_at": null,
    "void_reason": null,
    "voided_by": null,
    "created_at": "2026-09-23T01:34:49.722Z",
    "updated_at": "2026-09-23T01:34:51.125Z"
  }
}

Aprobar marca el auto vendido, un estado terminal, y anula en el mismo acto toda cotización que siguiera vigente sobre esa unidad:

{
  "data": {
    "id": "982dd531-6b1a-49f1-a947-f8520e7bb648",
    "tenant_id": "00000000-0000-4000-8000-000000000001",
    "display_id": "Q-7",
    "display_seq": 7,
    "vehicle_id": "de7d959a-292f-4491-92ce-2028fa9114f0",
    "buyer_contact_id": "01a0cbdd-304a-70d8-951f-5e4b481301c9",
    "salesperson_id": null,
    "list_price_clp": 8990000,
    "offered_price_clp": 8990000,
    "tax_treatment": "afecto",
    "discount_pct": 0,
    "unit_make": "Peugeot",
    "unit_model": "208",
    "unit_version": "Active 1.2",
    "unit_year": 2021,
    "unit_plate": "KXPW34",
    "unit_vin": "VF3CCHMZ6MT012345",
    "unit_odometer_value": 38200,
    "unit_odometer_unit": "KM",
    "unit_color": "Gris",
    "discount_hidden": false,
    "issued_at": "2026-09-23T01:24:47.318Z",
    "expires_on": "2026-09-30",
    "state": "nula",
    "voided_at": "2026-09-23T01:34:51.156Z",
    "void_reason": "Vehículo vendido (BR-215): la validez de una cotización vigente termina en el momento en que se vende la unidad, sin esperar a su fecha de expiración impresa — la validez es la que ocurra primero entre ambas.",
    "voided_by": "00000000-0000-0000-0000-000000000000",
    "extended_at": null,
    "extend_reason": null,
    "extended_by": null,
    "archived_at": null,
    "archive_reason": null,
    "archived_by": null,
    "created_at": "2026-09-23T01:24:47.318Z",
    "updated_at": "2026-09-23T01:34:51.125Z"
  }
}

Trampa

Un auto admite una sola nota de venta vigente

Emitir una segunda contra la misma unidad es 409, sin folio consumido.

{
  "error": {
    "code": "CONFLICT",
    "message": "Ya existe una nota de venta vigente (V-5) para este vehículo. Anúlala antes de emitir otra: un vehículo se vende una sola vez, y dos notas de venta vigentes sobre la misma unidad significan dos ventas del mismo auto. No se escribió nada y no se consumió ningún folio.",
    "requestId": "e41f51cc-48c5-40b8-8d1d-5c185b4ec6c5"
  }
}

Si net_clp cae bajo el nivel que la organización exige autorizar, approve responde 409. Hace falta una aprobación de precio resuelta a favor sobre ese mismo documento. La sección Autorizar un descuento muestra cómo se pide.

GET /sale-notes/{id} agrega totals y funding, el veredicto sobre si el dinero comprometido cubre el precio. Con las cifras completas y sin pagos registrados, standing es short; si falta tax_clp, el veredicto es not_computable y gaps dice qué falta. Anular pide sale_notes:void, una autoridad distinta de sale_notes:write.

Comprar

curl -X POST https://api.vitrinadev.com/api/v1/purchase-notes \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "seller_contact_id": "01a0cbdd-307a-75af-8566-1f9b09686cb8",
    "net_clp": 6200000,
    "tax_treatment": "no_gravado",
    "lines": [
      { "description": "Compra de vehículo usado Mazda CX-5 2020", "net_clp": 6200000, "tax_treatment": "no_gravado" }
    ]
  }'
{
  "data": {
    "id": "6e84a7d8-ccc0-4ed5-b03e-ec81613308e5",
    "tenant_id": "00000000-0000-4000-8000-000000000001",
    "display_id": "P-3",
    "display_seq": 3,
    "seller_contact_id": "01a0cbdd-307a-75af-8566-1f9b09686cb8",
    "net_clp": 6200000,
    "tax_clp": null,
    "tax_treatment": "no_gravado",
    "status": "issued",
    "issued_at": "2026-09-23T01:34:18.007Z",
    "corrected_at": null,
    "corrected_by": null,
    "voided_at": null,
    "void_reason": null,
    "voided_by": null,
    "created_at": "2026-09-23T01:34:18.007Z",
    "updated_at": "2026-09-23T01:34:18.007Z",
    "lines": [
      {
        "id": "e4be40c0-0f87-40be-8698-15feb843bbef",
        "tenant_id": "00000000-0000-4000-8000-000000000001",
        "purchase_note_id": "6e84a7d8-ccc0-4ed5-b03e-ec81613308e5",
        "sale_note_id": null,
        "position": 1,
        "description": "Compra de vehículo usado Mazda CX-5 2020",
        "net_clp": 6200000,
        "tax_clp": null,
        "tax_treatment": "no_gravado",
        "add_on_kind": null,
        "add_on_framing": null,
        "cost_clp": null,
        "beneficiary": null,
        "documents_in_customer_name": null,
        "fee_kind": null,
        "fee_effective_from": null,
        "created_at": "2026-09-23T01:34:18.007Z",
        "updated_at": "2026-09-23T01:34:18.007Z"
      }
    ],
    "acquisition": null,
    "retentions": []
  }
}

La nota de compra le da costo a un auto que entra al lote. Cada línea lleva su propio net_clp y su propio tax_treatment. El vínculo con la unidad se registra aparte, en /vehicle-acquisitions.

PATCH /purchase-notes/{id} corrige un documento vigente sin tocar su folio ni su estado, y deja corrected_at y corrected_by. lines reemplaza el desglose completo cuando lo envías.

Pagar

curl -X POST https://api.vitrinadev.com/api/v1/document-payments \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "reservation_id": "55923d26-8109-4d13-85aa-8ae2b9b10454",
    "instrument": "transferencia",
    "amount_clp": 300000,
    "paid_on": "2026-09-23",
    "bank": "Banco de Chile",
    "document_number": "8842190"
  }'
{
  "data": {
    "id": "01a0cbde-13ff-7fba-bc54-a0b8b687bcf1",
    "tenant_id": "00000000-0000-4000-8000-000000000001",
    "reservation_id": "55923d26-8109-4d13-85aa-8ae2b9b10454",
    "sale_note_id": null,
    "carried_from_reservation_id": null,
    "instrument": "transferencia",
    "amount_clp": 300000,
    "paid_on": "2026-09-23",
    "bank": "Banco de Chile",
    "account_number": null,
    "document_number": "8842190",
    "note": null,
    "card_fee_bps": null,
    "card_surcharge_clp": null,
    "card_surcharge_source": null,
    "created_at": "2026-09-23T01:25:24.095Z",
    "updated_at": "2026-09-23T01:25:24.095Z"
  }
}

Trampa

Una transferencia sin bank es 400

El instrumento decide qué campos se vuelven obligatorios: sin el banco, nadie puede cruzar la línea del estado de cuenta con el documento que pagó.

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "A transferencia payment requires bank (BR-261/BR-447): these are the fields that let the cashier match a bank statement line to a document, and without them a returned instrument cannot be traced back to the sale it paid for.",
    "requestId": "eb129b92-f686-4f4c-b62c-6cf19e6e57fa"
  }
}

Esta ruta se mantiene por compatibilidad. Para algo nuevo, la ruta es POST /payments: reparte un pago entre varias obligaciones, deja el sobrante como crédito del contacto y admite reverso.

Consignar

Bajo una consignación, la automotora vende el auto de otra persona. Solo vehicle_id y modalidad son obligatorios.

curl -X POST https://api.vitrinadev.com/api/v1/consignments \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "vehicle_id": "bd4490ca-587e-4396-b0dc-074b4997b8a1",
    "modalidad": "en_local"
  }'
{
  "data": {
    "id": "1357177d-cad8-49fa-8042-51ce1b1c4452",
    "tenant_id": "00000000-0000-4000-8000-000000000001",
    "vehicle_id": "bd4490ca-587e-4396-b0dc-074b4997b8a1",
    "dueno_contact_id": null,
    "modalidad": "en_local",
    "contract_structure": "mandato_con_representacion",
    "comision_type": null,
    "comision_value": null,
    "minimo_clp": null,
    "vencimiento": null,
    "estado": "activo",
    "vencimiento_reminded_at": null,
    "liquidacion_due_notified_at": null,
    "created_at": "2026-09-23T01:25:50.254Z",
    "updated_at": "2026-09-23T01:25:50.254Z",
    "sale_iva_regime": null,
    "not_on_lot": false
  }
}

Crear el contrato cambia la tenencia del auto a consignacion de inmediato. El dueño, la comisión y el mínimo se completan después con PATCH /consignments/{id}. Mientras falte la comisión, el contrato tampoco se puede vender:

{
  "error": {
    "code": "CONFLICT",
    "message": "Este contrato no tiene comisión registrada, así que no hay reparto que liquidar. Registra comision_type y comision_value en el contrato antes de venderlo.",
    "requestId": "7197732b-6386-47e9-9f84-fd1d12b3ac67"
  }
}

POST /consignments/{id}/sell transiciona el contrato a vendido y produce la liquidación en el mismo acto, con la comisión ya descontada:

{
  "data": {
    "contract": {
      "id": "1357177d-cad8-49fa-8042-51ce1b1c4452",
      "tenant_id": "00000000-0000-4000-8000-000000000001",
      "vehicle_id": "bd4490ca-587e-4396-b0dc-074b4997b8a1",
      "dueno_contact_id": "01a0cbdd-307a-75af-8566-1f9b09686cb8",
      "modalidad": "en_local",
      "contract_structure": "mandato_con_representacion",
      "comision_type": "percentage",
      "comision_value": 10,
      "minimo_clp": 12000000,
      "vencimiento": null,
      "estado": "vendido",
      "vencimiento_reminded_at": null,
      "liquidacion_due_notified_at": null,
      "created_at": "2026-09-23T01:25:50.254Z",
      "updated_at": "2026-09-23T01:26:12.646Z",
      "sale_iva_regime": null,
      "not_on_lot": false
    },
    "liquidacion": {
      "id": "765ad258-039c-43e6-b399-36b2e49ac281",
      "tenant_id": "00000000-0000-4000-8000-000000000001",
      "consignment_contract_id": "1357177d-cad8-49fa-8042-51ce1b1c4452",
      "vehicle_id": "bd4490ca-587e-4396-b0dc-074b4997b8a1",
      "settlement_mode": "stated_commission",
      "amount_venta_clp": 13890000,
      "comision_type": "percentage",
      "comision_value": 10,
      "comision_amount_clp": 1389000,
      "monto_owner_clp": 12501000,
      "owner_floor_clp": null,
      "deducciones_clp": 0,
      "retiro_motivo": null,
      "retiro_by": null,
      "paid_at": "2026-09-23T01:26:12.648Z",
      "created_at": "2026-09-23T01:26:12.646Z",
      "updated_at": "2026-09-23T01:26:12.646Z"
    }
  }
}

POST /consignments/{id}/return devuelve el auto a su dueño y la tenencia vuelve a propio. Es el único estado terminal que la restaura: un contrato vendido o vencido mantiene consignacion.

{
  "data": {
    "id": "42331a67-d7a0-45c2-8194-896a538edc42",
    "tenant_id": "00000000-0000-4000-8000-000000000001",
    "vehicle_id": "a4fb12d7-ef13-4871-b77e-0b80cda38303",
    "dueno_contact_id": "01a0cbdd-307a-75af-8566-1f9b09686cb8",
    "modalidad": "en_local",
    "contract_structure": "mandato_con_representacion",
    "comision_type": "percentage",
    "comision_value": 8,
    "minimo_clp": 7000000,
    "vencimiento": null,
    "estado": "devuelto",
    "vencimiento_reminded_at": null,
    "liquidacion_due_notified_at": null,
    "created_at": "2026-09-23T01:28:40.901Z",
    "updated_at": "2026-09-23T01:28:40.972Z",
    "sale_iva_regime": null,
    "not_on_lot": false
  }
}

Financiar

curl -X POST https://api.vitrinadev.com/api/v1/credit-applications \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "vehicle_id": "de7d959a-292f-4491-92ce-2028fa9114f0",
    "buyer_contact_id": "01a0cbdd-304a-70d8-951f-5e4b481301c9",
    "institution_id": "31512710-2c11-4ae2-b396-a394d7b82c16",
    "requested_amount_clp": 6500000,
    "term_months": 48
  }'
{
  "data": {
    "id": "09071d3d-e586-4415-ab98-03ef0bc681b3",
    "tenant_id": "00000000-0000-4000-8000-000000000001",
    "display_id": "F-3",
    "display_seq": 3,
    "vehicle_id": "de7d959a-292f-4491-92ce-2028fa9114f0",
    "buyer_contact_id": "01a0cbdd-304a-70d8-951f-5e4b481301c9",
    "institution_id": "31512710-2c11-4ae2-b396-a394d7b82c16",
    "requested_amount_clp": 6500000,
    "vehicle_price_clp": null,
    "declared_income_clp": null,
    "fee_clp": null,
    "term_months": 48,
    "financed_total_clp": null,
    "submitted_at": null,
    "submitted_by": null,
    "decided_at": null,
    "decided_by": null,
    "outcome": null,
    "decision_reason": null,
    "approved_amount_clp": null,
    "withdrawn_at": null,
    "withdrawn_by": null,
    "withdrawn_reason": null,
    "last_contact_at": null,
    "last_contact_by": null,
    "chased_at": null,
    "state": "recorded",
    "created_at": "2026-09-23T01:26:19.780Z",
    "updated_at": "2026-09-23T01:26:19.780Z",
    "taken": false,
    "taken_sale_note_id": null,
    "taken_sale_note_folio": null,
    "institution_name": "Banco Falabella",
    "taken_credit_state": null,
    "taken_disbursed_at": null,
    "vehicle_label": "Peugeot 208 2021",
    "vehicle_plate": "KXPW34",
    "buyer_name": "Daniela Ortiz",
    "buyer_rut": null
  }
}

El expediente avanza por hechos, cada uno con su propia ruta y ninguno una edición del estado. POST .../submission registra que la carpeta salió al banco, con el submitted_at que le pases. POST .../decision guarda la respuesta de la financiera, y outcome acepta approved o rejected. POST .../withdrawal retira el expediente y es terminal. POST .../contact reinicia el reloj de seguimiento y es el único repetible.

{
  "data": {
    "id": "09071d3d-e586-4415-ab98-03ef0bc681b3",
    "tenant_id": "00000000-0000-4000-8000-000000000001",
    "display_id": "F-3",
    "display_seq": 3,
    "vehicle_id": "de7d959a-292f-4491-92ce-2028fa9114f0",
    "buyer_contact_id": "01a0cbdd-304a-70d8-951f-5e4b481301c9",
    "institution_id": "31512710-2c11-4ae2-b396-a394d7b82c16",
    "requested_amount_clp": 6500000,
    "vehicle_price_clp": null,
    "declared_income_clp": null,
    "fee_clp": null,
    "term_months": 48,
    "financed_total_clp": null,
    "submitted_at": "2026-09-23T14:05:00.000Z",
    "submitted_by": "0eb8e217-8a6f-4cb8-8216-b077194b3df7",
    "decided_at": "2026-09-23T01:26:38.761Z",
    "decided_by": "0eb8e217-8a6f-4cb8-8216-b077194b3df7",
    "outcome": "approved",
    "decision_reason": null,
    "approved_amount_clp": 6000000,
    "withdrawn_at": null,
    "withdrawn_by": null,
    "withdrawn_reason": null,
    "last_contact_at": null,
    "last_contact_by": null,
    "chased_at": null,
    "state": "approved",
    "created_at": "2026-09-23T01:26:19.780Z",
    "updated_at": "2026-09-23T01:26:38.760Z",
    "taken": false,
    "taken_sale_note_id": null,
    "taken_sale_note_folio": null,
    "institution_name": "Banco Falabella",
    "taken_credit_state": null,
    "taken_disbursed_at": null,
    "vehicle_label": "Peugeot 208 2021",
    "vehicle_plate": "KXPW34",
    "buyer_name": "Daniela Ortiz",
    "buyer_rut": null
  }
}

GET /credit-applications/ageing es el tablero de cobranza con el reloj de cada financiera ya resuelto. No toma un parámetro de umbral: el plazo vive en el catálogo de instituciones y cada fila trae el suyo en sla_days.

Autorizar un descuento

curl -X POST https://api.vitrinadev.com/api/v1/price-approvals \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sale_note_id": "81d9aba3-3901-4ba6-963b-a176f20ae99b",
    "requested_price_clp": 7900000
  }'
{
  "data": {
    "id": "d0aace9b-bb03-40b1-9c09-1c2c7a08a2ac",
    "tenant_id": "00000000-0000-4000-8000-000000000001",
    "quote_id": null,
    "reservation_id": null,
    "sale_note_id": "81d9aba3-3901-4ba6-963b-a176f20ae99b",
    "requested_price_clp": 7900000,
    "list_price_snapshot_clp": 8990000,
    "floor_price_snapshot_clp": 8200000,
    "requester_user_id": "0eb8e217-8a6f-4cb8-8216-b077194b3df7",
    "status": "pending",
    "decider_user_id": null,
    "decided_at": null,
    "decision_note": null,
    "created_at": "2026-09-23T01:26:52.892Z",
    "updated_at": "2026-09-23T01:26:52.892Z"
  }
}

La solicitud nombra exactamente uno de quote_id, reservation_id o sale_note_id, y guarda el precio de lista y el piso tal como estaban. Pedir una autorización que nadie necesita es 400:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "10490000 needs no authorisation on V-2: it is at or above the reference this organisation approves against (tolerance 0 CLP). Sell it. An approval queue full of requests that needed no decision is a queue nobody reads.",
    "requestId": "8ec43ba3-0153-4697-9254-bc29ddd601b5"
  }
}

Trampa

Quien pide y quien decide tienen que ser personas distintas

POST /price-approvals/{id}/decision responde 403 cuando el decisor es el mismo principal que pidió la autorización.

{
  "error": {
    "code": "FORBIDDEN",
    "message": "You cannot approve or reject your own price request (BR-433/BR-434): the person who asks and the person who grants must differ. A discount authorised by its own beneficiary is not an authorisation. Ask somebody else holding price_approval:approve to decide it.",
    "requestId": "7b770694-1e04-481b-a51a-7fe238c967ce"
  }
}

Una decisión es terminal: no hay PUT, PATCH ni segunda decisión. Un rechazo tiene que traer decision_note; una aprobación puede ir sin comentario.

Eventos

Cada cambio de estado emite su propio evento: vehicle.published, vehicle.unpublished, vehicle.publish_failed, quote.issued, quote.voided, quote.extended, quote.archived, reservation.created, reservation.voided, reservation.abono_disposed, reservation.converted, sale_note.issued, sale_note.approved, sale_note.voided, purchase_note.issued, purchase_note.corrected, purchase_note.voided, payment.recorded, consignment.created, consignment.returned, consignment.sold, credit_application.recorded, credit_application.submitted, credit_application.decided, credit_application.withdrawn, price_approval.requested y price_approval.decided.

El catálogo completo, con el data_schema y una muestra de cada uno, está en Eventos suscribibles. Cómo suscribirte y verificar la firma está en Webhooks.

Referencia

Cada recurso tiene su página de referencia, generada del contrato. Las publicaciones viven dentro de Vehículos.

Cotizaciones · Reservas · Notas de venta · Notas de compra · Pagos de documentos · Consignaciones · Solicitudes de crédito · Aprobaciones de precio.

En esta página