DEVELOPERS·UPDATED 2026-07-29·sdk + api reference

Build in minutes, not weeks.

One SDK and one API for products, cart, native checkout, CMS content, and verified member identity — across Wix, Shopify, and Webflow. Install it, wrap your app, and ship. No migration, no glue services.

terminal
npm install trama-sdk @tanstack/react-query
§01

Three steps to your first product grid.

Wrap your app once with your project ID and a public key, then call the hooks anywhere. The provider handles caching, de-duplication, and refetching through TanStack Query.

Step 1 · Wrap your app

app/layout.tsx
import { TramaProvider } from 'trama-sdk';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <TramaProvider
      apiKey={process.env.NEXT_PUBLIC_TRAMA_KEY!}   // a tr_pub_ key — safe in the browser
      projectId="proj_xxxxxxxx"                     // from your dashboard
    >
      {children}
    </TramaProvider>
  );
}

Step 2 · Render products + cart

app/store/page.tsx
'use client';
import { useProducts, useCart } from 'trama-sdk';

export default function Store() {
  // useProducts wraps TanStack Query, so the array arrives on `data`.
  const { data: products, isLoading } = useProducts({ limit: 12 });
  const { addItem, goToCheckout } = useCart();

  if (isLoading) return <p>Loading…</p>;

  return (
    <div>
      {products?.map((p) => (
        <article key={p.id}>
          <h3>{p.name}</h3>
          <p>{p.price.formatted}</p>
          <button onClick={() => addItem(p.id, p.variants[0]?.id)}>Add to cart</button>
        </article>
      ))}
      <button onClick={goToCheckout}>Checkout →</button>
    </div>
  );
}

Step 3 · Ship

goToCheckout() redirects to your platform's native, hosted checkout — payments, taxes, and order creation stay on Wix, Shopify, or Webflow. You never touch payment code. Deploy to Vercel, Netlify, or anywhere React runs.


§02

Three key types. Know which goes where.

tr_pub_BrowserRead-only, origin-locked. The only key safe in frontend code. Set allowed origins in Settings → API keys.
tr_live_ServerFull-access production secret. Server-side only — never ship it to the browser.
tr_test_Server (dev)Same as live, for development and staging.

Keys are stored only as one-way hashes — the raw value is shown once at creation. Rotate or revoke any key anytime in Settings → API keys.


§03

React hooks for everything.

useProducts(options?)List products with filters + pagination.
useInfiniteProducts(options?)Cursor-style infinite product list.
useProduct(id)Fetch a single product by id.
useCollections()List all product collections.
useCart()Cart state + addItem / removeItem / updateQuantity / goToCheckout / clearCart.
useCheckout()Programmatic native-checkout creation.
useCmsItems(collectionId)Items from a content collection (Webflow CMS / Wix Data / Shopify metaobjects).
useAgencyComponent(name)Load an agency-deployed React component bundle.

Every hook is powered by TanStack Query — they cache, de-duplicate, and refetch on focus by default. Each normalized entity carries a metadata field with the raw platform payload, so you never lose access to native fields.


§04

Content sites, no storefront required.

Blog, marketing, and docs sites use the CMS surface on its own. Discover the connected site's collections — Webflow CMS collections, Wix Data collections, or Shopify metaobject types — then read their items.

app/blog/page.tsx
'use client';
import { useCmsItems } from 'trama-sdk';

export default function Blog() {
  const { items } = useCmsItems('blog-posts');  // collection id or slug
  return (
    <ul>
      {items.map((post: any) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

To enumerate collections server-side: await client.getCmsCollections().


§05

Gate content with verified members.

Your frontend logs the user in with the platform's own auth (Wix member login, Shopify customer login) and holds the session token. Your backend forwards it to Trama, which verifies it live against the platform and returns a trusted identity. Trama is a verifier — the platform stays the source of truth.

server: app/api/gate/route.ts
import { TramaClient } from 'trama-sdk';

const trama = new TramaClient({ apiKey: process.env.TRAMA_KEY!, projectId: 'proj_xxxxxxxx' });

export async function requireMember(platformToken: string) {
  const member = await trama.verifyMember(platformToken);
  if (!member) throw new Error('Not signed in');   // invalid / expired
  return member;
  // → { platformId, platform, email, firstName, lastName,
  //     tags: ['vip', 'course-access'], verifiedAt, metadata }
}

Shopify customer tags flow through for tier gating. Webflow has no native membership (User Accounts was discontinued), so verify returns a clear 501 — bring your own provider (below) and Trama keeps it in sync.

Bring your own provider — kept in sync.

Using Memberstack or Outseta for auth? Connect it in your project's Member Sync tab and Trama keeps your members in step with your backend — no glue services, no brittle automations to babysit. You get one normalized member, the same shape for every provider, delivered two ways: pushed to your webhook the moment it changes, and available to pull any time. Trama stays a connector — it never holds a session or gates auth, so you keep owning identity.

synced member (Memberstack / Outseta)
// Pull the latest synced member on demand
const res = await fetch(
  'https://api.gotrama.com/api/v1/members/synced/memberstack/' + memberId +
  '?projectId=proj_xxxxxxxx',
  { headers: { 'x-api-key': process.env.TRAMA_KEY! } },
);
const { data } = await res.json();
// data → { provider, externalId, email, firstName, lastName,
//          status: 'active', plans: ['pln_pro'], syncedAt }

// …or receive the same shape pushed to your webhook the instant it changes:
//   member.created · member.updated · member.deleted
//   member.backfill.completed — fired once when a backfill finishes,
//   with { syncedCount } so your backend knows to pull the full list

// Erase Trama's synced copy of one member (data-deletion requests):
//   DELETE /api/v1/members/synced/memberstack/{memberId}?projectId=…

Every event is verified before Trama accepts it, so what reaches your backend is authentic. Point the provider's webhook at the URL Trama gives you and you're live. Connecting an existing project? Run Backfill from the Member Sync tab and every member you already have is pulled in — it fills the store quietly (no event flood at your webhook) and fires a single member.backfill.completed event when it's done, so your backend knows exactly when to pull. When a member is deleted at the provider, Trama scrubs their personal data automatically, and the erase endpoint gives you a per-member deletion path for compliance requests.


§06

Catch AI-generated bugs before they ship.

A deterministic check — no AI involved — for the specific ways AI-generated frontend code breaks against a real commerce backend: wrong ID types on cart operations, raw price rendering, hardcoded secrets, platform constraints (Wix's hosted-checkout requirement, Shopify's variant/product ID split), and — once your project has a mapping — fields that were never actually mapped for your store.

check a real file against your project
# jq builds the JSON body so quotes/newlines in your source are escaped
# correctly — string-interpolating a real file's content directly into a
# curl -d payload breaks the moment the file has a double quote in it,
# which any real TSX/JSX file will.
curl -X POST https://api.gotrama.com/api/v1/correctness-check \
  -H "x-api-key: $TRAMA_KEY" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg source "$(cat ProductCard.tsx)" --arg filePath "ProductCard.tsx" \
        '{source: $source, filePath: $filePath}')"

No jq? Any JSON-aware language works fine too — the API just needs a valid JSON body with a source string. The dashboard's Correctness Check tab handles this for you if you'd rather not shell out.

Response shape: { data: { findings, hasBlockingFindings, ruleCount, platform } }. Each finding carries a severity (blocking / warning / info), a rule id, a plain-English message, and a line/column reference. Nothing you send is stored — only which rules fired.

Prefer a UI? Every project has a Correctness Check tab in the dashboard — paste a component, see findings inline. Included on every plan, with a monthly allowance that scales with plan tier (see pricing).


§07

Predictable errors, never a black box.

Every response uses one envelope. Errors carry a stable code, a human message, and a requestId for support — never a raw platform error or a leaked secret.

response envelope
// success
{ "success": true, "data": { /* ... */ }, "meta": { "cacheHit": true } }

// error
{ "success": false,
  "error": { "code": "…", "message": "human-readable message" },
  "requestId": "abc123" }

Handle non-2xx responses by the standard HTTP status: retry 429 after the Retry-After header (the SDK does this for you), re-authenticate on 401, and read error.message for everything else. Every error includes a requestId you can quote to support.

Under the hood: webhooks are signed, deduplicated, and retried automatically; transient failures recover on their own; and your integrations are continuously monitored so they keep working when a platform changes — you're alerted to issues before they reach your users.


§08

Keep building.

The SDK is fully typed, so your editor autocompletes every hook, argument, and response — you rarely need to leave your code. For a guided walkthrough tailored to your platform, see the headless guides for Wix, Shopify, and Webflow. For account, billing, and connection questions, the Help & FAQ has you covered. Still stuck? The support chat in the corner answers straight from these docs.