@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
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.
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:
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, likeidin/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:
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:
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:
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:
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:
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:
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:
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.