Skip to content

Cotizaciones

Una cotización (estimate) es una propuesta de venta con un vencimiento. No afecta el inventario ni genera cuentas por cobrar hasta que se convierte en una orden de venta.

La URL base de producción es https://api-pos.zelta.dev/public/v1 y todas las rutas se expresan relativas a ella. Todas las peticiones deben hacerse sobre HTTPS e incluir tu API key. Consulta .

INFO

A diferencia de las facturas y los ajustes, en las cotizaciones los ítems se pueden direccionar por id interno (cuid2) o por referenceId (identificador externo, máx. 120 caracteres). Debes enviar uno de los dos en cada línea.

Formulario de nueva cotización con cliente, sucursal, vigencia y productos
Desde el dashboard también puedes crear cotizaciones (cliente, vigencia, productos y notas). Por API, usa POST /estimates.

Crear una cotización

http
POST /estimates
CampoTipoRequeridoDescripción
clientIdstring (cuid2)NoCliente al que se dirige la cotización.
branchIdstring (cuid2)NoSucursal. Por defecto, la sucursal de la API key.
dueDatestring (ISO datetime)Fecha de vencimiento. Debe ser futura.
notesstring (≤2000)NoNotas de la cotización.
itemsarrayMínimo un ítem.
items[].idstring (cuid2)CondicionalIdentificador interno de la variante. Requerido si no se envía referenceId.
items[].referenceIdstring (≤120)CondicionalIdentificador externo. Requerido si no se envía id.
items[].quantitynumber (>0)Cantidad.
items[].pricenumberNoPrecio unitario. Por defecto, el del catálogo.
items[].discountnumber (≥0)NoDescuento por línea.
items[].taxnumber (0–100)NoTasa de impuesto por línea, en porcentaje.

TIP

Las cotizaciones aceptan impuesto por línea mediante el campo tax (tasa porcentual de 0 a 100). Si lo omites, se aplica la configuración de impuesto del catálogo del producto.

bash
curl -X POST "https://api-pos.zelta.dev/public/v1/estimates" \
  -H "Authorization: Bearer zpk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "clientId": "cl8h3k6m9p2q5v8r1n4t7w0y",
    "dueDate": "2026-02-28T23:59:59.000Z",
    "notes": "Cotización válida por 30 días",
    "items": [
      { "referenceId": "SKU-1001", "quantity": 5, "price": 19.90, "discount": 5, "tax": 7 },
      { "id": "pv1a3s5d7f9g2h4j6k8l0z2x", "quantity": 2 }
    ]
  }'

Ejemplo JS

javascript
const res = await fetch('https://api-pos.zelta.dev/public/v1/estimates', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${process.env.ZELTA_POS_API_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    clientId: 'cl8h3k6m9p2q5v8r1n4t7w0y',
    dueDate: '2026-02-28T23:59:59.000Z',
    notes: 'Cotización válida por 30 días',
    items: [
      { referenceId: 'SKU-1001', quantity: 5, price: 19.90, discount: 5, tax: 7 },
      { id: 'pv1a3s5d7f9g2h4j6k8l0z2x', quantity: 2 }
    ]
  })
});
const data = await res.json();

Ejemplo Py

python
import requests
res = requests.post(
    'https://api-pos.zelta.dev/public/v1/estimates',
    headers={'Authorization': 'Bearer zpk_live_xxx', 'Content-Type': 'application/json'},
    json={
        'clientId': 'cl8h3k6m9p2q5v8r1n4t7w0y',
        'dueDate': '2026-02-28T23:59:59.000Z',
        'notes': 'Cotización válida por 30 días',
        'items': [
            { 'referenceId': 'SKU-1001', 'quantity': 5, 'price': 19.90, 'discount': 5, 'tax': 7 },
            { 'id': 'pv1a3s5d7f9g2h4j6k8l0z2x', 'quantity': 2 }
        ]
    }
)
data = res.json()

Respuesta 201 Created:

json
{
  "id": "es2k5m8p1q4v7r0n3t6w9y2z",
  "number": "EST-000058",
  "clientId": "cl8h3k6m9p2q5v8r1n4t7w0y",
  "branchId": "br3b8n5k2j7h9g4f1d6s0a8q",
  "status": "draft",
  "subtotal": 137.30,
  "tax": 9.61,
  "total": 146.91,
  "notes": "Cotización válida por 30 días",
  "dueDate": "2026-02-28T23:59:59.000Z",
  "convertedOrderId": null,
  "items": [
    {
      "productVariantId": "pv9z2x4c6v8b1n3m5k7j9h2g",
      "name": "Camiseta básica - Talla M",
      "sku": "SKU-1001",
      "quantity": 5,
      "unitPrice": 19.90,
      "discount": 5,
      "taxRate": 7,
      "total": 99.86
    },
    {
      "productVariantId": "pv1a3s5d7f9g2h4j6k8l0z2x",
      "name": "Gorra deportiva",
      "sku": null,
      "quantity": 2,
      "unitPrice": 22.00,
      "discount": 0,
      "taxRate": 7,
      "total": 47.08
    }
  ],
  "createdAt": "2026-01-29T16:40:00.000Z",
  "updatedAt": "2026-01-29T16:40:00.000Z"
}

El campo status puede ser draft, accepted, expired o converted. Los campos clientId, notes, convertedOrderId y items[].sku pueden ser null.

Problemas comunes

CódigoHTTPCausa
validation_error400Falta dueDate, no es futura, o un ítem no trae id ni referenceId.
unauthorized401API key ausente o inválida.
not_found404El clientId, la branchId o una variante no existen.

Listar cotizaciones

http
GET /estimates

Acepta los parámetros de : start, limit, updatedSince, from, to y metadata.

bash
curl "https://api-pos.zelta.dev/public/v1/estimates?limit=30&metadata=true" \
  -H "Authorization: Bearer zpk_live_xxx"

Ejemplo JS

javascript
const res = await fetch('https://api-pos.zelta.dev/public/v1/estimates?limit=30&metadata=true', {
  headers: { 'Authorization': `Bearer ${process.env.ZELTA_POS_API_KEY}` }
});
const data = await res.json();

Ejemplo Py

python
import requests
res = requests.get(
    'https://api-pos.zelta.dev/public/v1/estimates',
    headers={'Authorization': 'Bearer zpk_live_xxx'},
    params={'limit': 30, 'metadata': 'true'}
)
data = res.json()

Respuesta 200 OK:

json
{
  "data": [
    {
      "id": "es2k5m8p1q4v7r0n3t6w9y2z",
      "number": "EST-000058",
      "clientId": "cl8h3k6m9p2q5v8r1n4t7w0y",
      "branchId": "br3b8n5k2j7h9g4f1d6s0a8q",
      "status": "draft",
      "subtotal": 137.30,
      "tax": 9.61,
      "total": 146.91,
      "dueDate": "2026-02-28T23:59:59.000Z",
      "convertedOrderId": null,
      "createdAt": "2026-01-29T16:40:00.000Z",
      "updatedAt": "2026-01-29T16:40:00.000Z"
    }
  ],
  "metadata": { "total": 58 }
}

Obtener una cotización

http
GET /estimates/{id}
CampoTipoRequeridoDescripción
idstring (cuid2)Identificador de la cotización.

Devuelve el objeto de la cotización directamente (sin envoltorio), con la misma estructura que la respuesta de creación. Si no existe, responde 404 not_found.

Siguientes pasos

  • — emite la venta cuando la cotización se acepta.
  • — gestiona los clientes a los que cotizas.
  • — revisa precios y existencias antes de cotizar.
  • — paginación, sincronización y códigos de error.

Documentación oficial de Zelta