Docs/Merchants

API reference

Every export from @obscura-app/merchant-sdk, one section per symbol.

obscura(config)

The merchant-side factory. Returns a ObscuraMerchantClient — a small object whose only method is charge().

ts
import { obscura } from "@obscura-app/merchant-sdk";

const pay = obscura(config: MerchantSdkConfig);

MerchantSdkConfig

OptionTypeRequiredDefaultDescription
merchantEtaAddressstringYesSolana pubkey (base58) of your Umbra encrypted token account. NOT a regular SPL wallet.
network"solana" | "solana-devnet"No"solana-devnet"Which Solana network to verify on.
mintstringNodevnet / mainnet USDCSPL token mint to accept. Must match the Obscura backend's STABLECOIN_MINT. NOTE: devnet today runs on WSOL — pass mint='So11111111111111111111111111111111111111112' explicitly when network='solana-devnet'.
decimalsnumberNo6Decimals for the mint. USDC = 6 (mainnet default). WSOL = 9 (devnet default — pass decimals: 9 explicitly).
rpcUrlstringNoSolana public RPCRPC endpoint for getTransaction reads during verification. Helius recommended for production.
replayWindowMsnumberNo300000Window during which a queueSignature is rejected on duplicate (default 5 min).

The factory throws synchronously on a missing or malformed merchantEtaAddress.

pay.charge(config)

Returns an Express-compatible middleware. Runs before your route handler, intercepts payment-less requests with a 402, and verifies payment-bearing requests on-chain before calling next().

ChargeConfig

OptionTypeRequiredDescription
amountstring (atomic units, e.g. "10000")YesPrice per call.
descriptionstringNoHuman-readable description included in the 402 body.
mimeTypestringNoResponse MIME advertised. Default application/json.
maxTimeoutSecondsnumberNoMax client wait for payment, in the 402 body. Default 300.
asset{ address: string; decimals: number }NoPer-route override of the SDK-default mint + decimals.

Side effects on res

On a successful verification, the middleware:

  • Sets an X-Payment-Response header — base64-encoded JSON of the settlement object.
  • Sets res.locals.obscuraSettlement — the parsed settlement object.
  • Calls next() so your downstream handler runs.

See Settlement receipts for reading them.

Re-exports

  • PaymentRequirements — the x402 type for a 402 challenge body. Useful for typing custom 402 handlers.
ts
import type { PaymentRequirements } from "@obscura-app/merchant-sdk";

type PaymentRequirements = {
scheme: "exact";
network: "solana" | "solana-devnet";
asset: string;
amount: string;
payTo: string;
resource: string;
maxTimeoutSeconds: number;
description?: string;
mimeType: string;
};
  • ObscuraMerchantClient — the type returned by obscura().

Protocol-level notes

  • Verification is direct chain read. The middleware calls getTransaction(queueSignature) (and getTransaction(callbackSignature) if present) via your configured RPC. No facilitator, no Obscura backend dependency at runtime.
  • Settlement is implicit. By the time the agent presents the envelope, the queue tx has landed and Arcium MPC has finalized. Nothing for the merchant to settle — the on-chain mixer commitment IS the settlement. Your encrypted balance is credited asynchronously by Obscura's claim daemon.
  • Replay protection is in-process. The SDK keeps an in-memory Map<queueSignature, seenAt> and rejects duplicates within replayWindowMs. For multi-process deployments, back this with Redis to close the cross-process replay window.
  • No Obscura API calls from the middleware. The SDK talks only to Solana RPC. Zero dependency on Obscura infrastructure on the request path.