# Obtener una venta

Permiso requerido: sales:read.

GET `/public/v1/sales/{id}`

Permiso `sales:read` · Ventas

## Parámetros

### Parámetros de ruta

| Nombre | Tipo          | Requerido | Descripción |
| ------ | ------------- | --------- | ----------- |
| `id`   | string (uuid) | Sí        | —           |

## Ejemplo de petición

**curl**

```sh
curl "https://api.posdata.so/public/v1/sales/3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d" \
  -H "Authorization: Bearer $POSDATA_API_KEY"
```

**Node.js**

```js
const res = await fetch('https://api.posdata.so/public/v1/sales/3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d', {
  headers: {
    Authorization: `Bearer ${process.env.POSDATA_API_KEY}`,
  },
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.error.code}: ${data.error.message} (${data.error.request_id})`);
```

**Python**

```python
import os

import requests

res = requests.get(
    "https://api.posdata.so/public/v1/sales/3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d",
    headers={
        "Authorization": f"Bearer {os.environ['POSDATA_API_KEY']}",
    },
    timeout=30,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{data['error']['code']}: {data['error']['message']} ({data['error']['request_id']})")
```

**PHP**

```php
<?php
$ch = curl_init('https://api.posdata.so/public/v1/sales/3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('POSDATA_API_KEY'),
    ],
]);
$data = json_decode(curl_exec($ch), true);
if (curl_getinfo($ch, CURLINFO_RESPONSE_CODE) >= 400) {
    throw new RuntimeException("{$data['error']['code']}: {$data['error']['message']} ({$data['error']['request_id']})");
}
```

## Respuesta

`200` OK: un objeto [Sale](https://developers.posdata.so/referencia/objetos/#obj-sale).

| Campo              | Tipo                                                                                                            | Requerido | Descripción                                                                                                                     |
| ------------------ | --------------------------------------------------------------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `object`           | `"sale"`                                                                                                        | Sí        | —                                                                                                                               |
| `id`               | string (uuid)                                                                                                   | Sí        | —                                                                                                                               |
| `status`           | string                                                                                                          | Sí        | Estado tal como lo registró el POS (completed, cancelled, open, pending…).                                                      |
| `document_kind`    | string                                                                                                          | Sí        | Documento que pidió el POS al cobrar. Valores: `pos`, `invoice`.                                                                |
| `payment_method`   | string                                                                                                          | Sí        | Medio de pago tal como lo registró el POS (CASH, CARD, NEQUI…).                                                                 |
| `customer_id`      | string (uuid) \| null                                                                                           | Sí        | —                                                                                                                               |
| `cash_session_id`  | string (uuid) \| null                                                                                           | Sí        | —                                                                                                                               |
| `subtotal`         | integer                                                                                                         | Sí        | Suma de las líneas, impuestos incluidos.                                                                                        |
| `discount`         | integer                                                                                                         | Sí        | Pesos colombianos (COP), entero sin decimales.                                                                                  |
| `discount_percent` | number                                                                                                          | Sí        | —                                                                                                                               |
| `tax`              | integer                                                                                                         | Sí        | Parte del total que es impuesto.                                                                                                |
| `tip_amount`       | integer                                                                                                         | Sí        | Propina. Nunca es base gravable.                                                                                                |
| `total`            | integer                                                                                                         | Sí        | subtotal - discount + tip_amount.                                                                                               |
| `tax_breakdown`    | arreglo de [TaxBreakdownEntry](https://developers.posdata.so/referencia/objetos/#obj-taxbreakdownentry) \| null | Sí        | —                                                                                                                               |
| `notes`            | string \| null                                                                                                  | Sí        | —                                                                                                                               |
| `table_label`      | string \| null                                                                                                  | Sí        | —                                                                                                                               |
| `items`            | arreglo de [SaleItem](https://developers.posdata.so/referencia/objetos/#obj-saleitem)                           | Sí        | —                                                                                                                               |
| `invoices`         | arreglo de [InvoiceSummary](https://developers.posdata.so/referencia/objetos/#obj-invoicesummary)               | Sí        | —                                                                                                                               |
| `occurred_at`      | string (date-time)                                                                                              | Sí        | Cuando se registró la venta en la caja (reloj de la caja). En ventas sincronizadas antes del 28-sep-2026 es la hora de llegada. |
| `created_at`       | string (date-time)                                                                                              | Sí        | Cuando la venta llegó al servidor (una caja sin conexión la sube después).                                                      |
| `updated_at`       | string (date-time)                                                                                              | Sí        | —                                                                                                                               |

```json
{
  "object": "sale",
  "id": "3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d",
  "status": "texto",
  "document_kind": "pos",
  "payment_method": "texto",
  "customer_id": "3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d",
  "cash_session_id": "3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d",
  "subtotal": 25900,
  "discount": 1,
  "discount_percent": 19,
  "tax": 1,
  "tip_amount": 25900,
  "total": 25900,
  "tax_breakdown": [
    {
      "code": "texto",
      "rate": null,
      "per_unit": null,
      "base": 1,
      "amount": 25900
    }
  ],
  "notes": "texto",
  "table_label": "texto",
  "items": [
    {
      "object": "sale_item",
      "id": "3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d",
      "product_id": "3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d",
      "variant_id": "3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d",
      "item_kind": "texto",
      "description": "texto",
      "quantity": 5,
      "unit_price": 25900,
      "subtotal": 25900,
      "unit_cost": 1,
      "tax_class": "texto",
      "taxes": [
        null
      ]
    }
  ],
  "invoices": [
    {
      "id": "3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d",
      "document_type": "electronic_invoice",
      "status": "texto",
      "cufe": "texto",
      "prefix": "texto",
      "number": 1
    }
  ],
  "occurred_at": "2026-09-28T15:04:05.000Z",
  "created_at": "2026-09-28T15:04:05.000Z",
  "updated_at": "2026-09-28T15:04:05.000Z"
}
```

## Errores

Todo error responde con un objeto [Error](https://developers.posdata.so/referencia/objetos/#obj-error) y un `request_id`. Ramifica por `error.code`, nunca por el mensaje.

### 400Petición inválida (VALIDATION_ERROR, INVALID_JSON, INVALID_CURSOR).

**Respuesta 400**

Cuerpo: un objeto [Error](https://developers.posdata.so/referencia/objetos/#obj-error). Qué significa cada código y qué hacer: [Errores](https://developers.posdata.so/errores/).

VALIDATION_ERRORINVALID_JSONINVALID_CURSOR

### 401Sin API key válida (UNAUTHENTICATED, INVALID_API_KEY, API_KEY_REVOKED, API_KEY_EXPIRED, API_KEY_WRONG_ENVIRONMENT, ACCOUNT_INACTIVE).

**Respuesta 401**

Cuerpo: un objeto [Error](https://developers.posdata.so/referencia/objetos/#obj-error). Qué significa cada código y qué hacer: [Errores](https://developers.posdata.so/errores/).

UNAUTHENTICATEDINVALID_API_KEYAPI_KEY_REVOKEDAPI_KEY_EXPIREDAPI_KEY_WRONG_ENVIRONMENTACCOUNT_INACTIVE

### 403Sin permiso (PLAN_REQUIRED, INSUFFICIENT_SCOPE, BROWSER_REQUESTS_NOT_ALLOWED).

**Respuesta 403**

Cuerpo: un objeto [Error](https://developers.posdata.so/referencia/objetos/#obj-error). Qué significa cada código y qué hacer: [Errores](https://developers.posdata.so/errores/).

PLAN_REQUIREDINSUFFICIENT_SCOPEBROWSER_REQUESTS_NOT_ALLOWED

### 404No existe en esta cuenta (NOT_FOUND).

**Respuesta 404**

Cuerpo: un objeto [Error](https://developers.posdata.so/referencia/objetos/#obj-error). Qué significa cada código y qué hacer: [Errores](https://developers.posdata.so/errores/).

NOT_FOUND

### 429Límite de peticiones (RATE_LIMITED). Respeta Retry-After.

**Respuesta 429**

Cuerpo: un objeto [Error](https://developers.posdata.so/referencia/objetos/#obj-error). Qué significa cada código y qué hacer: [Errores](https://developers.posdata.so/errores/).

RATE_LIMITED

### 500Error interno (INTERNAL_ERROR). Reintenta y comparte el request_id si persiste.

**Respuesta 500**

Cuerpo: un objeto [Error](https://developers.posdata.so/referencia/objetos/#obj-error). Qué significa cada código y qué hacer: [Errores](https://developers.posdata.so/errores/).

INTERNAL_ERROR

---

Fuente: https://developers.posdata.so/referencia/operations/getsale/ · Índice para agentes: https://developers.posdata.so/llms.txt
