SDKMerchant client

Merchant / low-level client — createFlightdeckClient

The raw, path-keyed typed client the storefront client is built on. It exposes a single method, request(), keyed off the generated paths type: method, path, the per-call args (path / query / header / body), and the return type are all checked against the OpenAPI spec — a typo in a path or a wrong body field does not compile.

Reach for it when you are on a merchant/operator surface holding an fdk_ credential, or when you need a spec path the storefront wrapper does not name.

Construction

import { createFlightdeckClient } from "@dscodotco/sdk";
 
const client = createFlightdeckClient({
  baseUrl: "https://api.ruo.pro",
  fdkToken: process.env.FDK_TOKEN,          // merchant Bearer credential
  // storefrontToken: process.env.FLIGHTDECK_STOREFRONT_TOKEN, // or the storefront credential
});

Options — FlightdeckClientOptions

OptionTypeRequiredNotes
baseUrlstringyesBase origin the paths resolve against, e.g. https://api.ruo.pro. A trailing slash is trimmed.
fdkTokenstringnoThe fdk_ merchant credential — sent as Authorization: Bearer <fdkToken>.
storefrontTokenstringnoThe narrow storefront credential — sent as x-storefront-token.
fetchtypeof fetchnoInjectable fetch. Defaults to the global fetch.

Construct a client with whichever credential(s) its surface uses. Both are optional individually, but a client with neither can only reach unauthenticated routes.

Auth-header behavior

The two credentials map to two headers, and both are sent when configured:

OptionHeader sent
fdkTokenAuthorization: Bearer <fdkToken>
storefrontTokenx-storefront-token: <storefrontToken>

These auth headers are the client’s own. A per-call header parameter (see below) can set operation-declared headers like Idempotency-Key, but it can never override authorization or x-storefront-token — those two names are ignored if you try to pass them per call. This keeps a request from silently re-authenticating as someone else.

⚠️

Both credentials are server-side secrets. The fdk_ merchant credential authorizes operator actions; the storefront token authorizes placing orders. Never construct this client in browser code.

The request() surface

request<P extends keyof paths, M extends MethodsOf<P>>(
  method: M,
  path: P,
  args?: RequestArgs<Operation<P, M>>,
): Promise<ResponseBody<Operation<P, M>>>
  • method"get" | "post" | "put" | "patch" | "delete", narrowed to the methods the chosen path actually defines.
  • path — any key of the generated paths. A path not in the spec does not compile.
  • args — optional; each part is typed to the operation:
args fieldPurpose
pathPath parameters filled into {…} segments (URL-encoded). A missing required path param throws before the request.
queryQuery parameters. undefined / null values are dropped; arrays repeat the key.
headerOperation-declared header parameters (e.g. Idempotency-Key). Cannot override the auth headers.
bodyJSON body. When present, content-type: application/json is set and the value is JSON.stringify-ed.

The resolved return type is the operation’s own generated 2xx body. A 204 (or any non-JSON success response) resolves to undefined. On a non-2xx it throws FlightdeckError carrying the parsed body.

Calling a merchant route

// Read one merchant order (fdk_ credential).
const order = await client.request("get", "/v1/merchant/orders/{id}", {
  path: { id: "ord_1" },
});
 
// Refund a merchant order — an operation-declared Idempotency-Key header.
await client.request("post", "/v1/merchant/orders/{id}/refund", {
  path: { id: "ord_1" },
  header: { "Idempotency-Key": `order-ord_1:refund-1` },
  body: { amount_cents: 1500, reason: "return accepted" },
});

The merchant surface in the spec today includes (non-exhaustive): orders (/v1/merchant/orders, /v1/merchant/orders/{id}, plus /refund and /cancel), the catalog list (/v1/merchant/catalog), subscriptions, webhooks and deliveries, gift cards, returns, marketing campaigns, and API credentials (/v1/my/credentials). Each is fully typed through request().

Calling a storefront path directly

The low-level client can call any storefront path too — useful for the ones the wrapper does not name (for example /v1/tenants/{tenant}/checkout/preview), or where a wrapper method omits a required query parameter. Send the storefrontToken and pass the query yourself:

const sf = createFlightdeckClient({
  baseUrl: "https://api.ruo.pro",
  storefrontToken: process.env.FLIGHTDECK_STOREFRONT_TOKEN,
});
 
// A single shopper order — the wrapper's shopper.order(id) cannot pass person_id,
// so reach the endpoint directly and supply it.
const one = await sf.request("get", "/v1/tenants/{tenant}/shopper/orders/{id}", {
  path: { tenant: "ruo-demo", id: orderId },
  query: { person_id },
});
 
// Read-only pricing preview (no named wrapper method).
const totals = await sf.request("post", "/v1/tenants/{tenant}/checkout/preview", {
  path: { tenant: "ruo-demo" },
  body: { items: [{ variant_id: variantId, quantity: 1 }], coupon_code: "SAVE10" },
});

The catalog-write gap

The SDK today is primarily a storefront (read + checkout) client. The merchant surface it can reach is largely read-oriented: /v1/merchant/catalog exposes only a get (list the tenant’s catalog). There are no catalog product create / update / delete operations in the generated spec — so there is no typed namespace for catalog writes, and, because request() is constrained to keyof paths, a catalog-write path is not even callable through the typed client without an escape hatch.

If you need catalog writes today, drive them through the console or the merchant API directly (outside the generated types) — for example a hand-built fetch against the merchant catalog write endpoints, carrying your fdk_ credential as Authorization: Bearer. When those routes land in the OpenAPI spec, they will become callable through request() (and, if wrapped, a named merchant namespace) in a future SDK release. Do not hand-edit the generated types to fake them in.

See also