> ## 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.

# Errores

> Capturá errores HTTP y errores estructurados de la API desde el SDK de TypeScript

El SDK lanza `LapymeError` para respuestas HTTP no exitosas. Cuando la API devuelve el envelope público, el error es `ApiErrorEnvelope` e incluye `requestId`, `error.code`, `error.type`, `error.message`, `error.retryable` y `error.details`.

```typescript theme={null}
import { Lapyme } from "lapyme";
import * as errors from "lapyme/models/errors";

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

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

try {
  await lapyme.sales.create({
    idempotencyKey,
    body: salePayload,
  });
} catch (error) {
  if (error instanceof errors.ApiErrorEnvelope) {
    console.error({
      requestId: error.requestId,
      code: error.error.code,
      message: error.error.message,
      details: error.error.details,
    });

    if (error.error.retryable) {
      // Reintentá la misma operación con el mismo idempotencyKey.
    }
  } else if (error instanceof errors.LapymeError) {
    console.error(error.statusCode);
    console.error(error.body);
  } else {
    throw error;
  }
}
```

## Helpers locales

Si querés centralizar el manejo de errores en tu integración, podés crear
helpers pequeños sobre las clases exportadas por el SDK.

```typescript theme={null}
import * as errors from "lapyme/models/errors";

export function isApiError(
  error: unknown,
  code?: string,
): error is errors.ApiErrorEnvelope {
  return (
    error instanceof errors.ApiErrorEnvelope &&
    (code === undefined || error.error.code === code)
  );
}

export function getRequestId(error: unknown): string | undefined {
  return error instanceof errors.ApiErrorEnvelope
    ? error.requestId
    : undefined;
}

export function isRetryable(error: unknown): boolean {
  return error instanceof errors.ApiErrorEnvelope && error.error.retryable;
}
```

## Códigos comunes

| Código                    | Qué significa                                              |
| ------------------------- | ---------------------------------------------------------- |
| `AUTHENTICATION_REQUIRED` | Falta el bearer token, es inválido o expiró.               |
| `FORBIDDEN`               | La credencial no tiene el scope requerido.                 |
| `INVALID_REQUEST`         | Hay parámetros o body inválidos.                           |
| `NOT_FOUND`               | El recurso no existe en la organización autenticada.       |
| `RATE_LIMITED`            | La organización superó una ventana de rate limit.          |
| `PRECONDITION_FAILED`     | Falta resolver una condición de negocio antes de ejecutar. |
| `IDEMPOTENCY_CONFLICT`    | La misma key se reutilizó con otro payload.                |

## Rate limit

Cuando recibís `RATE_LIMITED`, leé los headers de la respuesta para decidir cuándo reintentar.

```typescript theme={null}
import { Lapyme } from "lapyme";
import * as errors from "lapyme/models/errors";

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

try {
  await lapyme.products.list({ limit: 100 });
} catch (error) {
  if (
    error instanceof errors.ApiErrorEnvelope &&
    error.error.code === "RATE_LIMITED"
  ) {
    const retryAfter = error.headers.get("retry-after");
    console.log(`Reintentá en ${retryAfter ?? "unos"} segundos`);
  }
}
```

Para escrituras con `Idempotency-Key`, el retry debe reenviar la misma key y el
mismo payload de negocio. Si cambiás el payload con la misma key, la API devuelve
`IDEMPOTENCY_CONFLICT`.

<Info>
  Incluí `requestId` cuando contactes soporte. Es el identificador que permite rastrear la request.
</Info>
