@layerhop/sdk

Typed TypeScript client for the LayerHop API: best-price cross-chain and
same-chain swaps across EVM chains and Solana through one non-custodial API.
- Zero runtime dependencies. Uses the global
fetch; works in Node 18+, browsers, Deno, Bun, edge runtimes and React Native.
- ESM + CommonJS builds with bundled type definitions.
- Never holds keys. It fetches quotes and builds unsigned transactions; your wallet signs.
Install
npm install @layerhop/sdk
Quickstart
Amounts are always integer strings in base units (100 USDC = "100000000"), never floats.
import { LayerHop, LayerHopApiError } from "@layerhop/sdk";
const lh = new LayerHop({ apiKey: process.env.LAYERHOP_API_KEY, integrator: "myapp" });
const { best } = await lh.quote({
srcChain: "base", srcToken: "USDC", amount: "100000000",
dstChain: "solana", dstToken: "SOL",
sender: "0xYourEvmAddress", recipient: "YourSolanaAddress",
});
const tx = await lh.buildTx(best.quoteId);
Errors are thrown as LayerHopApiError with a stable code (see the
error catalog):
try {
await lh.buildTx(quoteId);
} catch (e) {
if (e instanceof LayerHopApiError && e.code === "QUOTE_EXPIRED") {
}
}
API
quote(params) | GET /v1/quote | Every successful quote, best for the user first. |
buildTx(quoteId) | POST /v1/orders | The unsigned transaction for a quote (EvmTx or SvmTx). |
submit(quoteId, signedTx) | POST /v1/orders/submit | Solana txs with submitViaApi: send the signed tx through LayerHop. |
reportSubmitted(quoteId, txHash) | POST /v1/orders/{quoteId}/submitted | Tell LayerHop the tx was broadcast. |
simulate(quoteId) | POST /v1/simulate | Dry-run the tx (EVM eth_call + gas, Solana simulateTransaction). |
listOrders(params) | GET /v1/orders | Orders from or to an address, newest first. |
status(provider, id) | GET /v1/orders/{provider}/{id} | Order status. |
watch(provider, id, opts?) | polls status | Async generator yielding each state change until final. |
serviceStatus() | GET /v1/status | Platform status (status.layerhop.com): components, 90-day uptime, incidents. |
checkout.create / get / list / expire / quote / stream | /v1/checkout/sessions | Checkout sessions ("pay with any token"). |
checkout.products.* | /v1/checkout/products | Fixed-price products for payment buttons and /buy/{id} links. |
checkout.refunds.create(sessionId, params?) / .list(sessionId) | /v1/checkout/sessions/{id}/refunds | Refund a paid session from your own wallet (build, sign, report). |
invoices.create / get / list / update / send / void | /v1/invoices | Invoices emailed to a customer and paid through checkout (API key). |
invoices.publicView(id) / invoices.pay(id) | /v1/invoices/{id}/public, /pay | The customer's side (public). |
subscriptions.create / get / list / update / cancel / pause / resume / invoices | /v1/subscriptions | Recurring billing: an invoice emailed every period (API key). |
depositAddresses.create / get / list / refresh / disable / simulate | /v1/deposit-addresses | Deposit addresses (beta): your user sends tokens to an address, no wallet connection (API key). |
Invoices and refunds
const lh = new LayerHop({ apiKey: process.env.LAYERHOP_API_KEY });
const invoice = await lh.invoices.create({
customerEmail: "ap@client.example",
lineItems: [{ description: "Design work", quantity: 2, unitAmount: "500000000" }],
settleChain: "base", settleToken: "USDC", recipient: "0xYourPayoutAddress",
send: true,
});
const sub = await lh.subscriptions.create({
customerEmail: "ada@example.com", interval: "month", description: "Pro plan",
amount: "49000000", settleChain: "base", settleToken: "USDC", recipient: "0xYourPayoutAddress",
});
await lh.subscriptions.cancel(sub.id, { atPeriodEnd: true });
const { refund, quote } = await lh.checkout.refunds.create("cs_...", { amount: "10000000", reason: "Partial refund" });
const tx = await lh.buildTx(quote.quoteId);
await lh.reportSubmitted(quote.quoteId, "0xTxHash");
Deposit addresses (beta)
const da = await lh.depositAddresses.create({
srcChain: "base", srcToken: "USDC", dstChain: "arbitrum", dstToken: "USDC",
recipient: "0xUserOnArbitrum", refundTo: "0xUserOnBase",
});
await lh.depositAddresses.refresh(da.id);
const { deposits } = await lh.depositAddresses.get(da.id);
await lh.depositAddresses.simulate(da.id, { amount: "25000000" });
Options for new LayerHop(options): baseUrl (default https://api.layerhop.com), apiKey,
channel, integrator, integratorFeeBps, fetch, streaming ("auto" | "fetch" | "xhr": how
Server-Sent Events streams are read; auto falls back to XMLHttpRequest where fetch can't stream, as in React Native).
The package also exports the chain and token registry (CHAINS, getChain, TOKENS, findToken,
SOLANA_CHAIN_ID, EVM_NATIVE, SOL_NATIVE) and all request/response types.
Full reference: https://docs.layerhop.com/sdk.
Related packages
License
MIT