VitrinaAPI

Vehicle attachments

Documents and files hanging off one unit.

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.

Keep and read the vehicle file explains this resource in prose, with runnable examples.

MethodPathWhat it does
GET/vehicle-attachmentsList the car's papers
POST/vehicle-attachmentsFile one of the car's papers (multipart/form-data)
DELETE/vehicle-attachments/{id}Delete one of the car's papers
PATCH/vehicle-attachments/{id}Rename a paper or set its «Vence» day
GET/vehicle-attachments/{id}/contentDownload the stored bytes of one attachment

GET /vehicle-attachments

List the car's papers

vehicle_id is required; there is no tenant-wide list of documents. Newest first. Each paper carries its kind, its label (an otro paper) and its expires_on («Vence»), when recorded.

expiring_within_days (ADR 0114 §7) narrows to the papers «Vencido» or due within that many days, soonest first, each with expiry_state; without vehicle_id it covers every car in stock and never returns a cédula or a paper naming a person. The same papers raise the vehicle_papers_expiring dealer alert and fill the Stock counts papers_expired / papers_expiring on GET /vehicles/stats.

ParameterInTypeRequiredConstraints
vehicle_idqueryuuidno
kindquerypadron \cedula \contrato \
expiring_within_daysqueryintegerno
curl https://api.vitrinadev.com/api/v1/vehicle-attachments \
  -H "Authorization: Bearer $VITRINA_KEY"

Example response (200)

{
  "data": [
    {
      "id": "f1f1f1f1-0000-4000-8000-000000000001",
      "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
      "vehicle_id": "e1e1e1e1-0000-4000-8000-000000000001",
      "kind": "padron",
      "storage_bucket": "vitrina-registry",
      "storage_path": "a1a1a1a1-0000-4000-8000-000000000001/e1e1e1e1-0000-4000-8000-000000000001/padron.png",
      "filename": "padron.png",
      "mime_type": "image/png",
      "byte_size": 812004,
      "subject_contact_id": null,
      "uploaded_by": "11111111-0000-4000-8000-000000000001",
      "uploaded_at": "2026-09-15T18:47:01.784Z",
      "created_at": "2026-09-15T18:47:01.784Z",
      "signed_document_type": null,
      "signed_document_id": null,
      "label": null,
      "expires_on": null
    },
    {
      "id": "f1f1f1f1-0000-4000-8000-000000000002",
      "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
      "vehicle_id": "e1e1e1e1-0000-4000-8000-000000000001",
      "kind": "cedula",
      "storage_bucket": "vitrina-registry",
      "storage_path": "a1a1a1a1-0000-4000-8000-000000000001/e1e1e1e1-0000-4000-8000-000000000001/cedula-consignante.png",
      "filename": "cedula-consignante.png",
      "mime_type": "image/png",
      "byte_size": 812004,
      "subject_contact_id": "22222222-0000-4000-8000-000000000001",
      "uploaded_by": "11111111-0000-4000-8000-000000000001",
      "uploaded_at": "2026-09-15T18:47:01.784Z",
      "created_at": "2026-09-15T18:47:01.784Z",
      "signed_document_type": null,
      "signed_document_id": null,
      "label": null,
      "expires_on": null
    },
    {
      "id": "f1f1f1f1-0000-4000-8000-000000000003",
      "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
      "vehicle_id": "e1e1e1e1-0000-4000-8000-000000000001",
      "kind": "contrato",
      "storage_bucket": "vitrina-registry",
      "storage_path": "a1a1a1a1-0000-4000-8000-000000000001/e1e1e1e1-0000-4000-8000-000000000001/compraventa-firmada.pdf",
      "filename": "compraventa-firmada.pdf",
      "mime_type": "application/pdf",
      "byte_size": 812004,
      "subject_contact_id": null,
      "uploaded_by": "11111111-0000-4000-8000-000000000001",
      "uploaded_at": "2026-09-15T18:47:01.784Z",
      "created_at": "2026-09-15T18:47:01.784Z",
      "signed_document_type": "compraventa",
      "signed_document_id": "d4d4d4d4-0000-4000-8000-000000000001",
      "label": null,
      "expires_on": null
    },
    {
      "id": "f1f1f1f1-0000-4000-8000-000000000004",
      "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
      "vehicle_id": "e1e1e1e1-0000-4000-8000-000000000001",
      "kind": "soap",
      "storage_bucket": "vitrina-registry",
      "storage_path": "a1a1a1a1-0000-4000-8000-000000000001/e1e1e1e1-0000-4000-8000-000000000001/soap-2027.jpg",
      "filename": "soap-2027.jpg",
      "mime_type": "image/jpeg",
      "byte_size": 812004,
      "subject_contact_id": null,
      "uploaded_by": "11111111-0000-4000-8000-000000000001",
      "uploaded_at": "2026-09-15T18:47:01.784Z",
      "created_at": "2026-09-15T18:47:01.784Z",
      "signed_document_type": null,
      "signed_document_id": null,
      "label": null,
      "expires_on": "2027-03-31"
    },
    {
      "id": "f1f1f1f1-0000-4000-8000-000000000005",
      "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
      "vehicle_id": "e1e1e1e1-0000-4000-8000-000000000001",
      "kind": "otro",
      "storage_bucket": "vitrina-registry",
      "storage_path": "a1a1a1a1-0000-4000-8000-000000000001/e1e1e1e1-0000-4000-8000-000000000001/informe.pdf",
      "filename": "informe.pdf",
      "mime_type": "application/pdf",
      "byte_size": 812004,
      "subject_contact_id": null,
      "uploaded_by": "11111111-0000-4000-8000-000000000001",
      "uploaded_at": "2026-09-15T18:47:01.784Z",
      "created_at": "2026-09-15T18:47:01.784Z",
      "signed_document_type": null,
      "signed_document_id": null,
      "label": "Informe mecánico",
      "expires_on": null
    }
  ]
}

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

POST /vehicle-attachments

File one of the car's papers (multipart/form-data)

Capped at the configured max size; the file part is required. PDF or an image (JPEG, PNG, WebP, HEIC, TIFF — a phone photo of a paper is fine).

THE CAR’S PAPERS (ADR 0114 §7): kind names the paper — permiso_circulacion, revision_tecnica, soap, padron, certificado_anotaciones (CAV), factura, contrato, cedula. Any other paper is otro with a label that names it («Factura de compra», «Informe mecánico»); a label with no kind files it as otro. expires_on records the day the paper stops being valid («Vence»). replaces_id supersedes a filed paper of the same kind: the old one is erased once the new one is filed.

A SIGNED COPY of one of the car’s documents (ADR 0114 §7) is filed with signed_document_type (purchase_note, sale_note, compraventa, consignment_contract, liquidacion) and signed_document_id (the nota de venta’s id for a compraventa, the consignación’s id for a liquidación). The document must be this car’s, and a compraventa must have been printed; kind may then be omitted — it is contrato for the compraventa and the mandato, otro for the rest — and a contradicting kind is refused (400). GET /vehicles/\{id\}/documents shows the copy on its document.

Or a JSON body (application/json) — what an MCP connector sends through call_operation, which cannot build multipart: \{ filename, content, content_encoding?, content_type? \} plus the operation's own form fields. content is UTF-8 text by default, or base64 when content_encoding is "base64" (images, PDF, audio, video). The same byte cap applies to the decoded bytes (413 above it); invalid base64 is a 400; the content type defaults from the filename extension.

Body

FieldTypeRequiredConstraints
filenamestringyesmín. 1, máx. 255
contentstringyesmín. 1, máx. 35000000
content_encodingutf8 \base64—
content_typestring—máx. 200
vehicle_iduuidyes
kindpadron \cedula \contrato \
subject_contact_iduuid—
signed_document_typepurchase_note \sale_note \compraventa \
signed_document_iduuid—
labelstring—máx. 120
expires_onany—
replaces_iduuid—
curl -X POST https://api.vitrinadev.com/api/v1/vehicle-attachments \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "vehicle_id": "e1e1e1e1-0000-4000-8000-000000000001",
    "kind": "soap",
    "expires_on": "2027-03-31",
    "file": "(binary file part)"
  }'

Example response (201)

{
  "data": {
    "id": "f1f1f1f1-0000-4000-8000-000000000001",
    "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
    "vehicle_id": "e1e1e1e1-0000-4000-8000-000000000001",
    "kind": "padron",
    "storage_bucket": "vitrina-registry",
    "storage_path": "a1a1a1a1-0000-4000-8000-000000000001/e1e1e1e1-0000-4000-8000-000000000001/padron.png",
    "filename": "padron.png",
    "mime_type": "image/png",
    "byte_size": 812004,
    "subject_contact_id": null,
    "uploaded_by": "11111111-0000-4000-8000-000000000001",
    "uploaded_at": "2026-09-15T18:47:01.784Z",
    "created_at": "2026-09-15T18:47:01.784Z",
    "signed_document_type": null,
    "signed_document_id": null,
    "label": null,
    "expires_on": null
  }
}

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

DELETE /vehicle-attachments/{id}

Delete one of the car's papers

Erases the storage object first, then the row. A paper still cited by a transferencia or a document discrepancy is refused (409) before anything is touched. Recorded in the car’s Historial.

ParameterInTypeRequiredConstraints
idpathuuidyes
curl -X DELETE https://api.vitrinadev.com/api/v1/vehicle-attachments/<id> \
  -H "Authorization: Bearer $VITRINA_KEY"

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

PATCH /vehicle-attachments/{id}

Rename a paper or set its «Vence» day

ADR 0114 §7 — corrects a filed paper without touching its file: label renames a paper filed as otro (a named kind — SOAP, padrón… — is named by its kind and refuses a label, 400); expires_on sets the day the paper stops being valid, null clears it. A new file is a replace (POST with replaces_id), not this. Recorded in the car’s Historial.

ParameterInTypeRequiredConstraints
idpathuuidyes

Body

FieldTypeRequiredConstraints
labelstring | null—máx. 120
expires_onstring | null—
curl -X PATCH https://api.vitrinadev.com/api/v1/vehicle-attachments/<id> \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "expires_on": "2027-03-31"
  }'

Example response (200)

{
  "data": {
    "id": "f1f1f1f1-0000-4000-8000-000000000001",
    "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
    "vehicle_id": "e1e1e1e1-0000-4000-8000-000000000001",
    "kind": "soap",
    "storage_bucket": "vitrina-registry",
    "storage_path": "a1a1a1a1-0000-4000-8000-000000000001/e1e1e1e1-0000-4000-8000-000000000001/padron.png",
    "filename": "padron.png",
    "mime_type": "image/png",
    "byte_size": 812004,
    "subject_contact_id": null,
    "uploaded_by": "11111111-0000-4000-8000-000000000001",
    "uploaded_at": "2026-09-15T18:47:01.784Z",
    "created_at": "2026-09-15T18:47:01.784Z",
    "signed_document_type": null,
    "signed_document_id": null,
    "label": null,
    "expires_on": "2027-03-31"
  }
}

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

GET /vehicle-attachments/{id}/content

Download the stored bytes of one attachment

Streams the raw file (not a JSON envelope) with Cache-Control: private, no-store and a locked-down CSP. Audited on every read.

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

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

On this page