VitrinaAPI

Price approvals

Authority over a below-reference price: the asker and the decider must be different people.

Beta
This may change at any time, with a changelog entry and a notice to recent callers — see versioning.

Download the full API pública projection: openapi.json.

Sell a unit explains this resource in prose, with runnable examples.

MethodPathWhat it does
GET/price-approvalsThe approval queue
POST/price-approvalsRequest approval for a below-reference price
GET/price-approvals/{id}Fetch one price approval
POST/price-approvals/{id}/decisionDecide a price approval
GET/price-approvals/evaluateWould this price need approval?

GET /price-approvals

The approval queue

Oldest-first. Cost fields (e.g. floor_price_snapshot_clp) are ABSENT from the response unless the caller also holds dealership_economics:read.

ParameterInTypeRequiredConstraints
statusquerypending \approved \rejected
subject_kindqueryquote \reservation \sale_note
subject_idquerystringnomín. 1, máx. 80
limitqueryintegerno≥ 1, ≤ 200, por defecto 50
offsetqueryinteger | nullno≥ 0, por defecto 0
curl https://api.vitrinadev.com/api/v1/price-approvals \
  -H "Authorization: Bearer $VITRINA_KEY"

Example response (200)

{
  "data": [
    {
      "id": "dbdbdbdb-0000-4000-8000-000000000001",
      "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
      "quote_id": null,
      "reservation_id": null,
      "sale_note_id": "d4d4d4d4-0000-4000-8000-000000000001",
      "requested_price_clp": 10900000,
      "list_price_snapshot_clp": 11900000,
      "floor_price_snapshot_clp": 11200000,
      "requester_user_id": "11111111-0000-4000-8000-000000000002",
      "status": "pending",
      "decider_user_id": null,
      "decided_at": null,
      "decision_note": null,
      "created_at": "2026-09-19T12:40:00.000Z",
      "updated_at": "2026-09-19T12:40:00.000Z"
    }
  ],
  "meta": {
    "total": 1
  }
}

Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429

POST /price-approvals

Request approval for a below-reference price

Names exactly one of quote_id / reservation_id / sale_note_id. requested_price_clp is the price the buyer pays for the car — IVA included on an afecto sale — the same terms as the published price and the precio piso it is measured against (ADR 0114 §2.2). A sale note is approved when what its buyer pays is at or above an approved request. The requester is the authenticated principal, never a body field.

Body

FieldTypeRequiredConstraints
quote_idany—
reservation_idany—
sale_note_idany—
requested_price_clpintegeryes≥ 0, ≤ 999999999999
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": "d4d4d4d4-0000-4000-8000-000000000001",
    "requested_price_clp": 10900000
  }'

Example response (201)

{
  "data": {
    "id": "dbdbdbdb-0000-4000-8000-000000000001",
    "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
    "quote_id": null,
    "reservation_id": null,
    "sale_note_id": "d4d4d4d4-0000-4000-8000-000000000001",
    "requested_price_clp": 10900000,
    "list_price_snapshot_clp": 11900000,
    "floor_price_snapshot_clp": 11200000,
    "requester_user_id": "11111111-0000-4000-8000-000000000002",
    "status": "pending",
    "decider_user_id": null,
    "decided_at": null,
    "decision_note": null,
    "created_at": "2026-09-19T12:40:00.000Z",
    "updated_at": "2026-09-19T12:40:00.000Z"
  }
}

Answers: 201 · 400 · 401 · 403 · 404 · 409 · 429

GET /price-approvals/{id}

Fetch one price approval

The approval as stored, whatever its status (pending | approved | rejected). Cost fields (list_price_snapshot_clp, floor_price_snapshot_clp) are ABSENT from the response — never null — unless the caller also holds dealership_economics:read, the same gate GET /price-approvals applies. An approval belonging to another workspace is a 404, indistinguishable from one that does not exist.

ParameterInTypeRequiredConstraints
idpathuuidyes
curl https://api.vitrinadev.com/api/v1/price-approvals/<id> \
  -H "Authorization: Bearer $VITRINA_KEY"

Example response (200)

{
  "data": {
    "id": "dbdbdbdb-0000-4000-8000-000000000001",
    "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
    "quote_id": null,
    "reservation_id": null,
    "sale_note_id": "d4d4d4d4-0000-4000-8000-000000000001",
    "requested_price_clp": 10900000,
    "list_price_snapshot_clp": 11900000,
    "floor_price_snapshot_clp": 11200000,
    "requester_user_id": "11111111-0000-4000-8000-000000000002",
    "status": "pending",
    "decider_user_id": null,
    "decided_at": null,
    "decision_note": null,
    "created_at": "2026-09-19T12:40:00.000Z",
    "updated_at": "2026-09-19T12:40:00.000Z"
  }
}

Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429

POST /price-approvals/{id}/decision

Decide a price approval

Terminal — no PUT/PATCH and no second decision. price_approval:approve is a single, non-OR’d scope: holding the requesting scope never grants the deciding authority.

ParameterInTypeRequiredConstraints
idpathuuidyes

Body

FieldTypeRequiredConstraints
decisionapproved \rejectedyes
decision_notestring | null—máx. 2000
curl -X POST https://api.vitrinadev.com/api/v1/price-approvals/<id>/decision \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "decision": "approved",
    "decision_note": "autorizado por gerencia dado el tiempo en stock"
  }'

Example response (200)

{
  "data": {
    "id": "dbdbdbdb-0000-4000-8000-000000000001",
    "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
    "quote_id": null,
    "reservation_id": null,
    "sale_note_id": "d4d4d4d4-0000-4000-8000-000000000001",
    "requested_price_clp": 10900000,
    "list_price_snapshot_clp": 11900000,
    "floor_price_snapshot_clp": 11200000,
    "requester_user_id": "11111111-0000-4000-8000-000000000002",
    "status": "approved",
    "decider_user_id": "11111111-0000-4000-8000-000000000001",
    "decided_at": "2026-09-19T16:05:00.000Z",
    "decision_note": "autorizado por gerencia dado el tiempo en stock",
    "created_at": "2026-09-19T12:40:00.000Z",
    "updated_at": "2026-09-19T12:40:00.000Z"
  }
}

Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429

GET /price-approvals/evaluate

Would this price need approval?

Evaluates price_clp — what the buyer pays for the car, IVA included on an afecto sale, the same terms as the published price and the precio piso (ADR 0114 §2.2) — against the unit named by exactly one of vehicle_id / quote_id / reservation_id / sale_note_id (UUID or folio), with the same policy POST /price-approvals enforces — so a screen that hides «Pedir aprobación» on needs_approval: false hides exactly the request the POST would refuse. reason is the stable code (below_reference | within_tolerance | at_or_above_reference | no_reference); message is a ready-to-show Spanish sentence. When the reference is the unit floor, reference_clp and shortfall_clp are ABSENT unless the caller holds dealership_economics:read. Requires price_approval:read or price_approval:request.

ParameterInTypeRequiredConstraints
vehicle_idqueryuuidno
quote_idqueryanyno
reservation_idqueryanyno
sale_note_idqueryanyno
price_clpquerystringyespatrón ^\d{1,12}$
curl https://api.vitrinadev.com/api/v1/price-approvals/evaluate \
  -H "Authorization: Bearer $VITRINA_KEY"

Example response (200)

{
  "data": {
    "needs_approval": true,
    "reason": "below_reference",
    "message": "El precio está $500.000 bajo el precio publicado ($12.990.000). Requiere la aprobación de otra persona.",
    "reference_kind": "list",
    "reference_clp": 12990000,
    "shortfall_clp": 500000,
    "tolerance_clp": 0,
    "vehicle_id": "5b0c7a7e-2f3d-4c1e-9a4b-7d2e8f1c3a60"
  }
}

Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429

On this page