> ## Documentation Index
> Fetch the complete documentation index at: https://docs.snappy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Place Digital Card Orders

> End-to-end flow for ordering a digital card (gift card, prepaid card, or similar) through the V3 Orders API — including how to retrieve the digital card ID, redemption URL, and access code.

* **This pattern covers the full flow for issuing a digital gift card, prepaid card, or similar card-based reward through Snappy's V3 APIs.** Digital cards are ordered through the same `POST /v3/orders` endpoint as physical items, with a lighter address (only `countryCode` is required).
* **A digital card entity is created behind the scenes** as a result of placing the order. It captures the card-specific details of that order — access card URL, authentication method, amount, recipient, and brand — and is retrievable via the [Digital Cards API](/modules/api/v3/digital-cards/overview).
* **The last step of the pattern depends on the authentication method configured for your Company.** Authentication is a Company-level setting: Snappy configures it during onboarding, and it applies to every digital card your Company issues — you don't need to check `authentication.method` per card.
  * If your Company is on **`OTP`** (Snappy's default), Snappy handles recipient redemption end-to-end. Nothing else to do after the order is placed.
  * If your Company is on **`accessCode`**, retrieve the static access code from the Digital Cards API and send it to the recipient through your own channel.

## Prerequisites

* API key with `orders:create` scope (and `digitalCards:read` if your Company is on `accessCode`)
* A configured billing method under the ordering Account
* `Snappy-Account-Id` header set on every request

## Step 1 — Find a digital card variant

Digital card products live in a dedicated catalog. Filter the products endpoint by `filter[catalog]=digitalCards` to browse what's available, then pick a specific variant for the order.

```text theme={null}
GET /v3/products?filter[catalog]=digitalCards
```

```javascript JavaScript theme={null}
async function findDigitalCardVariants({ location = "US" } = {}) {
  const url = new URL(`${SNAPPY}/v3/products`);
  url.searchParams.set("filter[catalog]", "digitalCards");
  url.searchParams.set("location", location);
  url.searchParams.set("include", "brand");
  const res = await fetch(url, { headers });
  const { data } = await res.json();
  return data;
}
```

The order is placed against a **variant**, not a product. Pick the variant matching the denomination (e.g., \$25 Amazon gift card) your recipient should receive.

## Step 2 — Place the order

Call `POST /v3/orders` with the digital card variant, the recipient details, and a minimal `shippingAddress` containing only `countryCode`. See [Place Orders](/patterns/place-orders) for the underlying mechanics.

```javascript JavaScript theme={null}
async function placeDigitalCardOrder({ variantId, recipient, idempotencyKey, tags, metadata }) {
  const res = await fetch(`${SNAPPY}/v3/orders`, {
    method: "POST",
    headers: {
      ...headers,
      "Snappy-Account-Id": process.env.SNAPPY_ACCOUNT_ID,
    },
    body: JSON.stringify({
      billingMethodId: process.env.SNAPPY_BILLING_METHOD_ID,
      variantId,                                        // a digitalCards catalog variant
      recipient: {
        firstName: recipient.firstName,
        lastName: recipient.lastName,
        email: recipient.email,                         // digital cards are delivered by email
        phone: recipient.phone,                         // E.164, required
      },
      shippingAddress: {
        countryCode: recipient.countryCode,             // only field required for digital variants
      },
      idempotencyKey,                                   // stable per redemption attempt
      tags,
      metadata,
    }),
  });
  if (!res.ok) throw new Error(`Order failed ${res.status}: ${await res.text()}`);
  const { data } = await res.json();
  return data; // { id: orderId, status: "active", trackingLink }
}
```

The response is the standard order-placement envelope: `{ id, status, trackingLink }`. Save `orderId` — you'll use it in Step 3 to look up the digital card.

<Tip>
  Snappy uses `countryCode` to price and localize the digital card. Set it to the recipient's country even though there's no physical shipment.
</Tip>

## Step 3 — Retrieve the digital card

A digital card entity is created automatically when the order is processed. Look it up by `orderId`:

```text theme={null}
GET /v3/digital-cards?filter[orderId]={orderId}
```

```javascript JavaScript theme={null}
async function getDigitalCardForOrder(orderId) {
  const url = new URL(`${SNAPPY}/v3/digital-cards`);
  url.searchParams.set("filter[orderId]", orderId);
  url.searchParams.set("include", "brand");
  const res = await fetch(url, { headers });
  const { data } = await res.json();
  return data[0]; // typically one card per order
}
```

The response is a JSON:API-style envelope: `{ data: [...], links: {...} }`. Each digital card in `data` carries:

* **`id`** — the stable `digitalCardId`. Use this to fetch the access code (Step 4) if applicable.
* **`url`** — the Snappy-hosted **access card page**. The recipient opens this URL to authenticate (OTP or access code) and then reach the gift card provider to complete redemption. Share it with the recipient or embed it in your own notification.
* **`authentication.method`** — `OTP` or `accessCode`. Matches your Company's configured method.
* **`amount`** — `{ value, currency }`, the card's denomination.
* **`recipient`** — `{ name, email }` for the person the card was issued to.
* **`orderId`**, **`companyId`**, **`createdAt`** — provenance fields for reconciliation with your own records.
* **`brand`** — the card issuer (only when `include=brand` is set), e.g., Amazon, Visa, Starbucks.

## Step 4 — Retrieve the access code (`accessCode` only)

**Skip this step if your Company is on `OTP`.** Snappy handles OTP redemption end-to-end — there's no static code to retrieve, and the recipient receives everything they need from Snappy's notifications.

For `accessCode` integrations, fetch the static code that Snappy generated when the card was issued:

```text theme={null}
GET /v3/digital-cards/{digitalCardId}/access-code
```

```javascript JavaScript theme={null}
async function getAccessCode(digitalCardId) {
  const res = await fetch(`${SNAPPY}/v3/digital-cards/${digitalCardId}/access-code`, { headers });
  if (!res.ok) throw new Error(`Access code fetch failed ${res.status}: ${await res.text()}`);
  const { data } = await res.json();
  return data; // { digitalCardId, accessCode }
}
```

The response is `{ data: { digitalCardId, accessCode } }`. The code is sensitive — the endpoint requires the `digitalCards:read` scope and is designed for server-side consumption.

<Warning>
  Never expose the access code to your frontend, mobile client, or third-party analytics. Fetch it server-side and pass it directly into the recipient notification your backend sends.
</Warning>

## Step 5 — Deliver to the recipient

The last step is on your side and depends on your Company's authentication method:

* **`OTP`** — nothing to do. Snappy has already sent the recipient a notification with the redemption `url`. When they open the page, Snappy issues a fresh OTP to authenticate them.
* **`accessCode`** — send the recipient a message through your own channel (email, SMS, in-app notification, portal message). Include the `url` from Step 3 and the `accessCode` from Step 4. Typically these go together in a single "your reward is ready" notification.

<Tip>
  For `accessCode` integrations, wait until Step 4 succeeds before sending the notification — you want to include both the URL and the code, and you don't want to send a notification pointing at a URL that will fail redemption because the code isn't ready yet.
</Tip>

## Full flow example

Putting it together for an `accessCode` Company:

```javascript JavaScript theme={null}
// 1. Place the order
const order = await placeDigitalCardOrder({
  variantId: "variant_abc123",
  recipient: {
    firstName: "Jane",
    lastName: "Doe",
    email: "jane@example.com",
    phone: "+12133734253",
    countryCode: "US",
  },
  idempotencyKey: `dgtc-${redemptionId}`,
  tags: ["digital-card", "reward"],
  metadata: { program: "loyalty", externalRecipientId: "crm-user-987" },
});

// 2. Retrieve the digital card (retry with backoff if not immediately available)
const card = await getDigitalCardForOrder(order.id);

// 3. If on accessCode, fetch the code
const { accessCode } = await getAccessCode(card.id);

// 4. Send the recipient your own notification with card.url + accessCode
await sendRecipientNotification({
  to: "jane@example.com",
  url: card.url,
  code: accessCode,
});
```

For an `OTP` Company, skip steps 3-4 — Snappy sends the recipient a notification and manages the redemption.

## Failure table

| HTTP  | Meaning                                                                                   | Action                                                                                                           |
| :---- | :---------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------- |
| `422` | Non-digital variant supplied to `POST /v3/orders` (variant with `shippingRequired: true`) | Confirm the variant came from `filter[catalog]=digitalCards`; physical variants require a full shipping address. |
| `422` | Insufficient funds on billing method                                                      | Alert your ops team; this is a billing issue.                                                                    |
| `404` | `variantId`, `billingMethodId`, or `accountId` not found                                  | Config bug on your side — log and fail safe.                                                                     |
| `422` | `GET /v3/digital-cards/{digitalCardId}/access-code` returns 422                           | Your Company is on `OTP` — don't call this endpoint; use the access card URL instead.                            |

## Related

* [Place Orders](/patterns/place-orders) — general order placement mechanics
* [Digital Cards API overview](/modules/api/v3/digital-cards/overview) — the full API surface for retrieving digital cards
* [Track Order Fulfillment](/patterns/track-order-fulfillment) — webhook signals to know when a digital card is ready to fetch
