Get startedQuickstart

Quickstart

This is first contact with the Flightdeck commerce API. By the end you will have made an authenticated request, read a store’s public catalog, and placed a first order — with both curl and the @dscodotco/sdk typed client.

The live API used by the RUO Pro vertical is:

  • Production: https://api.ruo.pro
  • Local development: http://localhost:3000

What a credential looks like

There are two credential types, and which one you hold decides what you can do.

  • A merchant credential is an opaque bearer key prefixed fdk_. It is tenant-scoped: the tenant it acts on and the scopes it is allowed are carried by the key itself, never by the path or body. Send it as Authorization: Bearer fdk_....
  • A storefront token is an opaque secret (no fixed prefix) sent on its own header, x-storefront-token: <token>. It is narrow — it places checkouts and reads a shopper’s own data for one deployment — and today it is a single platform-wide static secret (one shared token, not per-tenant; per-tenant scoping is planned). The tenant comes from the URL path.

Both are secrets. Keep them server-side; never ship either in browser code. See Authentication for the full model.

From zero to a placed order

Make an authenticated request

Confirm your merchant credential works by listing the credentials it can see. The tenant is resolved from the key — you never pass it.

curl https://api.ruo.pro/v1/my/credentials \
  -H "Authorization: Bearer fdk_your_key_here"

A 200 returns { "credentials": [ ... ] } (metadata only — key material is never returned). A 401 means the key is missing, malformed, or revoked.

Read the public catalog

A store’s active catalog is the one deliberately public, unauthenticated read surface. No credential is required — only the tenant slug in the path:

curl https://api.ruo.pro/v1/tenants/nova-peptide/catalog/products

The response is { "products": [ ... ] }, each product carrying its variants. Prices are integer cents (price_cents). You need a variant_id from here to place an order.

List the catalog with the SDK

Install the typed client and read the same catalog. The client is tenant-pinned: you set the tenant once and it is pinned into every request path.

npm install @dscodotco/sdk
import { createStorefrontClient } from "@dscodotco/sdk";
 
const store = createStorefrontClient({
  apiUrl: "https://api.ruo.pro",
  tenant: "nova-peptide",
  storefrontToken: process.env.FLIGHTDECK_STOREFRONT_TOKEN!, // server-side only
});
 
const { products } = await store.products.list();

Every field is typed from the API’s OpenAPI document — a wrong query or body field is a compile error, not a runtime surprise.

Place a first checkout

Checkout is one shot: you submit the cart and the card together, and the platform prices the authoritative total, runs the fraud floor, captures payment, and places the order. It sends card fields, so it must run server-side.

Every money-mutating call requires an Idempotency-Key header. Make it deterministic — derive it from the business event (cart id + attempt), never a fresh random value — so a retried request replays the original outcome instead of charging twice.

curl -X POST https://api.ruo.pro/v1/tenants/nova-peptide/checkout \
  -H "x-storefront-token: your_storefront_token" \
  -H "Idempotency-Key: cart-8c1f2a:attempt-1" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_ref": "guest:shopper@example.com",
    "items": [{ "variant_id": "var_123", "quantity": 1 }],
    "card": { "ccnumber": "4111111111111111", "ccexp": "12/28", "cvv": "123" }
  }'

The same call with the SDK — the idempotency key is the required second argument, sent as the Idempotency-Key header:

const result = await store.checkout.submit(
  {
    customer_ref: "guest:shopper@example.com",
    items: [{ variant_id: "var_123", quantity: 1 }],
    card: { ccnumber: "4111111111111111", ccexp: "12/28", cvv: "123" },
  },
  { idempotencyKey: `cart-${cartId}:attempt-1` },
);
 
// result.order.id, result.order.total_cents, result.card_charged_cents

A 201 is a fresh placement; a 200 with outcome: "already_placed" is an idempotent replay of the same key — treat it as success. A decline is a 4xx and the SDK throws FlightdeckError. See Checkout for the full body (coupons, store credit, gift cards, shipping/tax policy) and every outcome branch.

Next steps