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

# Promotions & Discount Codes

> Create percentage and fixed-amount discounts, coupon codes, and conditional promotions

# Promotions & Discount Codes

**Time**: \~10 minutes | **Difficulty**: Intermediate

Use the Node SDK to define **promotions** (automatic or code-based discounts) with **rules** (when they apply) and **actions** (what they do). Attach human-readable **promotion codes** so customers can enter coupons at checkout.

<Info>
  Promotions are scoped to a **store** (`storeId`). Amounts in money fields are typically in the **smallest currency unit** (e.g. cents for USD) unless noted otherwise in your dashboard.
</Info>

***

## Prerequisites

| Requirement           | How to get it                                                         |
| --------------------- | --------------------------------------------------------------------- |
| Node.js 18+           | [nodejs.org](https://nodejs.org)                                      |
| `@tagadapay/node-sdk` | `npm install @tagadapay/node-sdk`                                     |
| API key               | Dashboard → Settings → API Keys                                       |
| A store               | [Merchant Quick Start](/developer-tools/node-sdk/merchant-quickstart) |

```ts theme={null}
import Tagada from '@tagadapay/node-sdk';

const tagada = new Tagada('your-api-key');
const STORE_ID = 'store_...';
```

***

## Initialize and (optional) create a target product

Line-item discounts often reference a **product id**. For a store-wide percentage off, you can skip this.

```ts theme={null}
const product = await tagada.products.create({
  storeId: STORE_ID,
  name: 'Promo target product',
  active: true,
  isShippable: false,
  isTaxable: false,
  variants: [{
    name: 'Default',
    sku: 'PROMO-001',
    grams: null,
    active: true,
    default: true,
    price: null,
    compareAtPrice: null,
    prices: [{
      currencyOptions: { USD: { amount: 5000 } },
      recurring: false,
      billingTiming: 'usage',
      interval: null,
      intervalCount: 1,
      default: true,
    }],
  }],
});
```

<Tip>
  `5000` in `currencyOptions` = **\$50.00** when the currency is USD (cents).
</Tip>

***

## Create a percentage order discount (20% off)

Apply a percentage to the **whole order** with `OrderAdjustment` and `adjustmentType: 'percentage'`.

```ts theme={null}
const promotion = await tagada.promotions.create({
  storeId: STORE_ID,
  name: '20% off entire order',
  enabled: true,
  automatic: true,
  actions: [{
    type: 'OrderAdjustment',
    adjustmentType: 'percentage',
    adjustmentPercentage: 20,
  }],
});
```

<Note>
  `automatic: true` means the promotion can apply without a coupon when your rules (if any) are satisfied. Set `automatic: false` when you only want it to apply via a **promotion code**.
</Note>

***

## Create a fixed line-item discount (\$10 off a specific product)

Use `LineItemAdjustment` with `adjustmentType: 'amount'` and `adjustmentAmount` in the **full currency object** shape (not just `{ USD: 1000 }`).

```ts theme={null}
const lineItemPromo = await tagada.promotions.create({
  storeId: STORE_ID,
  name: '$10 off selected product',
  enabled: true,
  automatic: false,
  actions: [{
    type: 'LineItemAdjustment',
    adjustmentType: 'amount',
    adjustmentAmount: {
      USD: {
        amount: 1000, // $10.00 in cents
        rate: 1,
        lock: false,
        date: '2026-01-01',
      },
    },
    targetProductId: product.id,
    targetVariantIds: null,
    maxQuantityDiscounted: null,
    appliesOnEachItem: false,
  }],
});
```

<Info>
  **`adjustmentAmount` format:** each currency key maps to `{ amount, rate, lock, date }`. Use an ISO date string (or timestamp) for `date` as required by your environment. `rate`, `lock`, and `date` participate in currency conversion and locking behavior on the platform.
</Info>

***

## Conditional promotion: free shipping over \$30

Combine **`OrderAmountMinimum`** in `rules` with **`ShippingAdjustment`** in `actions`.

```ts theme={null}
const freeShippingPromo = await tagada.promotions.create({
  storeId: STORE_ID,
  name: 'Free shipping on orders $30+',
  enabled: true,
  automatic: true,
  rules: [{
    type: 'OrderAmountMinimum',
    minimumAmount: {
      USD: {
        amount: 3000, // $30.00
        rate: 1,
        lock: false,
        date: '2026-01-01',
      },
    },
  }],
  actions: [{
    type: 'ShippingAdjustment',
    freeShipping: true,
  }],
});
```

***

## Create a promotion code (coupon)

Link a reusable **code** to an existing promotion. Customers enter the code at checkout; the promotion’s rules and actions then apply.

```ts theme={null}
const promotionCode = await tagada.promotionCodes.create({
  promotionId: lineItemPromo.id,
  code: 'SAVE10',
  active: true,
});
```

<Tip>
  Create the **promotion** first, then call `promotionCodes.create` with its `promotionId`. You can attach multiple codes to the same promotion if your workflow allows it.
</Tip>

***

## List, retrieve, update, and delete promotions

### List

```ts theme={null}
const listResult = await tagada.promotions.list({ storeId: STORE_ID });
// Shape may include `promotions`, `items`, or a raw array — normalize in your app
```

### Retrieve

`storeId` is **required** for a reliable lookup in multi-store accounts.

```ts theme={null}
const one = await tagada.promotions.retrieve(promotion.id, STORE_ID);
```

### Update

Updates are wrapped in a **`data`** object alongside `id`.

```ts theme={null}
const updated = await tagada.promotions.update({
  id: promotion.id,
  data: {
    storeId: STORE_ID,
    name: '25% off entire order',
    enabled: true,
    automatic: true,
    actions: [{
      type: 'OrderAdjustment',
      adjustmentType: 'percentage',
      adjustmentPercentage: 25,
    }],
  },
});
```

### Delete

Pass an **array of ids** and `storeId`.

```ts theme={null}
await tagada.promotions.del([promotion.id, lineItemPromo.id], STORE_ID);
```

<Note>
  Some API responses nest the resource under `promotion` or `promotionCode`. When creating resources, read `result.id` or `result.promotion?.id` depending on the payload shape.
</Note>

***

## Promotion rules reference

| Rule type                    | Purpose                                                                     |
| ---------------------------- | --------------------------------------------------------------------------- |
| `ContainsProduct`            | Order must include specific product(s) / variant(s)                         |
| `OrderAmountMinimum`         | Subtotal (or qualifying amount) must meet a minimum, using currency objects |
| `OrderMinQuantity`           | Minimum total line-item quantity on the order                               |
| `OrderMaxQuantity`           | Maximum total line-item quantity on the order                               |
| `MaxProductQuantity`         | Cap quantity eligible for the discount per product                          |
| `PaymentIntegrationSelected` | Restrict to orders using a specific processor / payment integration         |

***

## Promotion actions reference

| Action type                     | What it does                                  | Common fields                                                                                                                                                                              |
| ------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `LineItemAdjustment`            | Discount specific lines                       | `adjustmentType`: `'percentage'` \| `'amount'`; `adjustmentPercentage` or `adjustmentAmount`; optional `targetProductId`, `targetVariantIds`, `maxQuantityDiscounted`, `appliesOnEachItem` |
| `OrderAdjustment`               | Discount the whole order                      | `adjustmentType`: `'percentage'` \| `'amount'`; `adjustmentPercentage` or order-level `adjustmentAmount`                                                                                   |
| `ShippingAdjustment`            | Change shipping charges                       | e.g. `freeShipping: true`                                                                                                                                                                  |
| `CreateLineItem`                | Add a line item when the promotion fires      | Product / variant / quantity configuration (per your store setup)                                                                                                                          |
| `SubscriptionLineItemFreeTrial` | Apply a free trial on subscription line items | Trial duration / terms as supported by the platform                                                                                                                                        |

***

## SDK methods: `tagada.promotions`

| Method     | Signature (conceptual)                                                          | Description                               |
| ---------- | ------------------------------------------------------------------------------- | ----------------------------------------- |
| `create`   | `promotions.create({ storeId, name, enabled, automatic, actions, rules, ... })` | Create a promotion                        |
| `list`     | `promotions.list({ storeId })`                                                  | List promotions for a store               |
| `retrieve` | `promotions.retrieve(id, storeId)`                                              | Get one promotion; **`storeId` required** |
| `update`   | `promotions.update({ id, data: { storeId, name, ... } })`                       | Update fields inside **`data`**           |
| `del`      | `promotions.del(ids[], storeId)`                                                | Delete one or more promotions             |

***

## SDK methods: `tagada.promotionCodes`

| Method   | Signature (conceptual)                                 | Description                               |
| -------- | ------------------------------------------------------ | ----------------------------------------- |
| `create` | `promotionCodes.create({ promotionId, code, active })` | Create a coupon linked to a promotion     |
| `list`   | `promotionCodes.list()`                                | List promotion codes                      |
| `update` | `promotionCodes.update({ ... })`                       | Update an existing code (e.g. deactivate) |
| `del`    | `promotionCodes.del(ids[])`                            | Delete codes by id                        |

***

## Currency amount shape

Whenever the API expects a **currency map** (e.g. `adjustmentAmount`, `minimumAmount`), use:

```ts theme={null}
{
  USD: {
    amount: 1000,       // smallest unit (e.g. cents)
    rate: 1,
    lock: false,
    date: '2026-01-01', // ISO date string
  },
}
```

Repeat keys (`EUR`, `GBP`, …) for multi-currency stores as needed.

***

## Next steps

<CardGroup cols={2}>
  <Card title="Merchant Quick Start" icon="rocket" href="/developer-tools/node-sdk/merchant-quickstart">
    Store, product, funnel, and checkout session setup
  </Card>

  <Card title="Upsell & Downsell Funnel" icon="arrow-up-right-dots" href="/developer-tools/node-sdk/upsell-downsell-funnel">
    Post-purchase offers and conditional funnel routing
  </Card>

  <Card title="Custom Checkout" icon="paintbrush" href="/developer-tools/node-sdk/custom-checkout">
    Advanced checkout flows with the Node SDK
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/introduction">
    Full REST API documentation
  </Card>
</CardGroup>
