Reference

Build on the Lucra API.

Drag a sticker to move it, or use the arrow keys while focused.

SDK

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

@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

Terminal
npm install @lucra/sdk

Create a client

Create a client with an API key from Settings → Developers → API, or an OAuth access token. Keep either on your server.

TypeScript
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:

TypeScript
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:

TypeScript
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:

TypeScript
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:

TypeScript
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 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:

TypeScript
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:

TypeScript
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 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:

TypeScript
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 covers the whole flow.

Other languages

Generate a client from the OpenAPI document, or call the API over HTTP.