# SDK

> The TypeScript client: calls, pagination, errors and embeds.

Source: https://www.onlucra.com/docs/sdk

`@lucra/sdk` is the TypeScript client for the Lucra API. It has a typed method for every endpoint, sends the version header for you, and throws one error type. It runs anywhere `fetch` does: Node 18+, Bun, Deno and Workers.

## Install

```bash
npm install @lucra/sdk
```

## Create a client

Create a client with an API key from **Settings → Developers → API**, or an [OAuth](https://www.onlucra.com/docs/oauth) access token. Keep either on your server.

```ts
import { Lucra } from "@lucra/sdk"

const lucra = new Lucra(process.env.LUCRA_API_KEY!)
```

## Make a call

Methods are named `lucra.<resource>.<action>`, with actions `list`, `retrieve`, `create` and `update`. This gets one program:

```ts
const { data: program } = await lucra.programs.retrieve({
  path: { id: "prog_00lhuAJjQgdtNt5WnqTBc95" },
})
```

Every method takes one object with up to three parts, and resolves to `{ data, response }`:

- `path`: the IDs in the URL, like `id` in `/v1/programs/:id`.
- `query`: filters and paging for lists.
- `body`: the fields to create or change.

This pauses the program, sending its `version` so it fails if someone else changed it first:

```ts
await lucra.programs.update({
  path: { id: program.id },
  body: { status: "paused", version: program.version },
})
```

Nested resources follow the path: `lucra.balance.transactions.list(…)` calls `GET /v1/balance/transactions`. Every model is exported as a type, like `Program`, `Creator` or `Payment`.

## Lists

A list's `data` is one page: its items are in `data.data`, and `data.nextCursor` points to the next page. This gets the first page of submissions waiting for review:

```ts
const { data: page } = await lucra.submissions.list({
  query: { program: "prog_00lhuAJjQgdtNt5WnqTBc95", status: "pending" },
})
console.log(page.data, page.nextCursor)
```

## Every page

`paginate` walks every page for you, fetching the next one as you loop. Pass filters as its second argument:

```ts
import { paginate } from "@lucra/sdk"

const pending = paginate((options) => lucra.payments.list(options), {
  query: { status: "pending_approval" },
})
for await (const payment of pending) console.log(payment.id, payment.net)
```

## Act for an account

A [partner](https://www.onlucra.com/docs/api-partners) acts for a client brand (`acct_…`) or a roster creator (`crtr_…`). `lucra.as(id)` returns the same client, sending that account in the `Lucra-Account` header:

```ts
const brand = lucra.as("acct_07RodMW6bE7BBO6e1I3UzSi")
const { data: page } = await brand.programs.list()
```

To act for one account everywhere, pass it when you create the client: `new Lucra(key, { account: "acct_…" })`.

## Errors

A failed request throws a `LucraError`. Branch on `code`, which is stable; show `message` or `fix` to people:

```ts
import { LucraError } from "@lucra/sdk"

try {
  await lucra.programs.retrieve({ path: { id: "prog_00lhuAJjQgdtNt5WnqTBc95" } })
} catch (error) {
  if (!(error instanceof LucraError)) throw error
  if (error.code === "program_not_found") console.log("No such program")
  else console.error(error.status, error.code, error.message, error.fix)
}
```

`LucraError` has `status`, `code`, `message` (the API's `detail`), `fix`, `retryable`, `requestId`, and `errors`, one per invalid field. A network failure is thrown as it is, not as a `LucraError`. See [Errors](https://www.onlucra.com/docs/api-introduction#errors) for the codes.

## Retries

Send an `Idempotency-Key` header on a write you might retry, so a retry never writes twice. Writes that move money require one. Use an ID from your own system, like an order ID:

```ts
await lucra.payments.create({
  body: { creator: "crtr_026UYfiw1Y6OvUpuKWiOpeL", net: 5000, note: "Launch bonus" },
  headers: { "Idempotency-Key": "order-1042-bonus" },
})
```

## Embeds

The same package puts Lucra's screens in your app. Open an embed on your server with `lucra.embeds.create`, then mount it in the browser with `@lucra/sdk/embed`, or with React components from `@lucra/sdk/react`:

```tsx
import { loadLucra, LucraProvider, LucraWallet } from "@lucra/sdk/react"

// Your server route calls lucra.embeds.create and returns its clientSecret.
const lucra = loadLucra({
  fetchClientSecret: () => fetch("/api/lucra-embed", { method: "POST" }).then((r) => r.json()).then((r) => r.clientSecret),
})

export const Wallet = () => (
  <LucraProvider lucra={lucra}>
    <LucraWallet />
  </LucraProvider>
)
```

[Embeds](https://www.onlucra.com/docs/embeds) covers the whole flow.

## Other languages

Generate a client from the [OpenAPI document](https://api.onlucra.com/v1/openapi.json), or call the API over HTTP.
