Skip to main content
This walks through a first call against the sandbox environment, which serves a seeded demo catalog so you can build before wiring up your own data.
1

Get an Org-API-Key

Create a developer account and a sandbox key in the developer portal. The key is a server-side secret - keep it on your backend.
2

Install an SDK

npm install @expys/sdk
3

Mint a member token from your backend

The app never holds the Org-API-Key. Your backend exchanges it for a short-lived member token scoped to one of your users:
curl -X POST https://api.expys.com/v1/auth/exchange \
  -H "Authorization: Bearer YOUR_ORG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "externalUserID": "user_123" }'
The response is a TokenGrant - an accessToken and an expiresAt. Hand the accessToken to the app. See Authentication for the full refresh contract.
4

Browse and redeem

Initialize the SDK with the member token and run the data flow - check eligibility, list offers, and redeem the first one:
import { ConflictError, initialize } from "@expys/sdk";

const token = process.env.EXPYS_MEMBER_TOKEN;
if (!token) {
  throw new Error(
    "Set EXPYS_MEMBER_TOKEN (a member token from your backend's /v1/auth/exchange)",
  );
}

const expys = initialize({
  baseUrl: process.env.EXPYS_BASE_URL,
  environment: "sandbox",
  token,
});

async function main(): Promise<void> {
  const eligibility = await expys.eligibility();
  console.log(
    `tier: ${eligibility.tier}, balance: ${eligibility.wallet.balance}`,
  );

  const { data: offers } = await expys.listOffers({ limit: 10 });
  console.log(`browsed ${offers.length} offers`);

  const offer = offers[0];
  if (!offer) {
    return;
  }

  console.log(`redeeming: ${offer.title} (${offer.id})`);
  try {
    const redemption = await expys.createRedemption({ offer: offer.id });
    console.log(`redemption created: ${redemption.id} [${redemption.status}]`);

    const status = await expys.getRedemption(redemption.id);
    console.log(`status now: ${status.status}`);
  } catch (error) {
    if (error instanceof ConflictError) {
      console.log(`already redeemed: ${error.code}`);
      return;
    }
    throw error;
  }
}
Run it with the member token in the environment:
EXPYS_MEMBER_TOKEN=... <run your example>
A successful run prints the member’s tier and balance, the number of offers browsed, and a new redemption id with its status. If a redemption already exists for that offer, the SDK raises a REDEMPTION_ALREADY_EXISTS conflict - see Errors.

Next steps

Authentication and refresh

The two-token model and how the SDK refreshes member tokens.

Environments

How sandbox and live differ, and how the key selects one.

Redemptions

Points spend, idempotency, and the redemption lifecycle.

Errors and retries

The error taxonomy, stable codes, and retry behavior.