> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lapyme.com.ar/llms.txt
> Use this file to discover all available pages before exploring further.

# Ejemplo: crear una venta

> Registrá una venta con el SDK de TypeScript usando un Idempotency-Key estable

Crear una venta es el primer flujo recomendado para probar una integración real:
envía un payload de negocio, impacta los efectos que correspondan y devuelve una
respuesta tipada con `requestId`, datos persistidos, efectos y warnings.

```typescript theme={null}
import { Lapyme } from "lapyme";

const lapyme = new Lapyme({
  bearerAuth: process.env["LAPYME_API_KEY"] ?? "",
});

const externalOrderId = "shopify-1001";

const sale = await lapyme.sales.create({
  idempotencyKey: `sale:shopify:${externalOrderId}`,
  body: {
    customerId: "9c692e8b-0f9a-4f7c-8b99-061a2eb188ae",
    pointOfSaleId: "8d3e9c5a-0b1d-4a8c-9b55-4f1d6b6d4a10",
    integrationSource: "SHOPIFY",
    integrationId: externalOrderId,
    voucherType: 6,
    invoiceDate: new Date(),
    currency: "PES",
    notes: `Pedido externo ${externalOrderId}`,
    items: [
      {
        productId: "4fb3af29-4ee4-4a8d-8b20-9a95b2431b73",
        quantity: 1,
        unitPrice: 125000,
      },
    ],
  },
});

console.log({
  requestId: sale.result.requestId,
  sale: sale.result.data.sale,
  effects: sale.result.data.projectedEffects,
  warnings: sale.result.warnings,
});
```

## Descargar el comprobante

El detalle de una venta incluye `document.file`. Cuando su `status` es
`ready`, `url` contiene una ruta estable de la API, por ejemplo
`/api/v1/sales/{sale_id}/document`. Esa ruta requiere la misma API key con
`sales:read` y responde con un redirect `302` hacia una URL firmada de cinco
minutos.

```typescript theme={null}
const detail = await lapyme.sales.getSaleById({
  saleId: sale.result.data.sale.id,
});

const documentUrl = detail.result.data.document?.file?.url;

if (documentUrl) {
  const response = await fetch(`https://api.lapyme.com.ar${documentUrl}`, {
    headers: {
      Authorization: `Bearer ${process.env.LAPYME_API_KEY}`,
    },
    redirect: "follow",
  });

  if (!response.ok) {
    throw new Error(await response.text());
  }

  const invoicePdf = await response.arrayBuffer();
}
```

Si el comprobante todavía se está generando, el endpoint de descarga responde
`409 PRECONDITION_FAILED`, `retryable: true` y `Retry-After: 5`. Si la
generación falló, responde `409` con `retryable: false`. Leer o descargar nunca
inicia una regeneración.

<Info>
  La ruta autenticada `document.file.url` es para integraciones. El `Location`
  firmado existe solo para transferir el archivo y no debe persistirse. Los links
  públicos opacos `/comprobantes/d/{token}` usados en emails son credenciales de
  portador distintas; la ruta pública histórica usada por WhatsApp tampoco forma
  parte del contrato de la API.
</Info>

## Reintentos seguros

Si tu worker, backend o job reintenta la misma venta, reenviá el mismo
`idempotencyKey`. No generes una key nueva para cada intento del mismo pedido.
La clave de idempotencia no se guarda como referencia externa de la venta; si
necesitás ver o buscar el ID de tu sistema, envialo también en
`integrationSource` e `integrationId`.

```typescript theme={null}
const idempotencyKey = `sale:shopify:${externalOrderId}`;

await lapyme.sales.create({
  idempotencyKey,
  body: salePayload,
});
```

<Tip>
  Usá importes monetarios en centavos. Por ejemplo, `$1.250,00` se envía como
  `125000`.
</Tip>
