Applying Discounts to Payments

Frame Payments provides a comprehensive discount system that enables you to create flexible promotional campaigns and apply them seamlessly to customer payments. This guide explains how to set up discounts, generate customer-facing codes, and apply them at checkout.

For detailed API specifications and parameters, please refer to our Coupons API documentation and Promotion Codes API documentation.

Understanding the Discount System

Frame's discount system uses a two-tier architecture designed for flexibility and control:

  • Coupons are reusable discount templates that define the discount rules, duration, and restrictions.
  • Promotion Codes are the customer-facing codes generated from coupons that customers enter at checkout.
  • Charge Intents accept promotion codes to automatically calculate and apply discounts.

This separation allows you to create a single discount rule (coupon) and generate multiple unique codes from it, each with its own expiration dates, usage limits, and targeting options.

Discount Workflow Overview

The process of creating and applying discounts involves three main steps:

  1. Create a Coupon Template

    • Define your discount structure (percentage or fixed amount).
    • Set validity periods, usage limits, and minimum order requirements.
    • Configure which products the discount applies to.
  2. Generate Promotion Codes

    • Create customer-facing codes from your coupon template.
    • Set code-specific restrictions (expiration, customer targeting, first-time buyer only).
    • Generate multiple codes from a single coupon for different distribution channels.
  3. Apply Codes at Checkout

    • Customers enter promotion codes when creating a charge intent.
    • Frame automatically validates eligibility and calculates the discount.
    • Support for stacking up to 20 codes per transaction.

Step 1: Creating a Coupon Template

Begin by creating a coupon that defines your discount structure. The coupon acts as a reusable template for generating customer-facing promotion codes.

Example: Summer Sale Coupon

POST/v1/coupons
curl --request POST \
  --url https://api.framepayments.com/v1/coupons \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "SUMMER2025_20PCT",
  "description": "Summer sale - 20% off all orders",
  "discount_type": "percentage",
  "discount_value": 20,
  "duration": "once",
  "status": "active",
  "applicable_to": "all_products",
  "max_redemptions": 1000,
  "minimum_order_amount_cents": 5000,
  "minimum_order_amount_currency": "USD",
  "discount_cap_cents": 10000,
  "discount_cap_currency": "USD",
  "valid_from": "2025-06-01T00:00:00Z",
  "valid_until": "2025-08-31T23:59:59Z",
  "metadata": {
    "campaign": "summer_2025"
  }
}'

Configuration Options

  • Discount Type: Choose percentage (e.g., 20% off) or fixed_amount (e.g., $10 off).
  • Duration:
    • once - Applies to a single purchase only.
    • repeating - Applies for a specified number of billing cycles (requires duration_in_months).
    • forever - Applies indefinitely to all eligible purchases.
  • Applicable To: Restrict to all_products or specific_products using product_id.
  • Minimum Order Amount: Set a minimum purchase requirement to qualify for the discount.
  • Discount Cap: Limit the maximum discount amount (useful for percentage discounts).
  • Max Redemptions: Control how many times the coupon can be used across all customers.

After creating the coupon, save the returned id - you'll need it to generate promotion codes.

Step 2: Generating Promotion Codes

Once you have a coupon template, create customer-facing promotion codes that inherit the coupon's discount rules but can have their own specific restrictions.

Creating Multiple Codes from One Coupon

You can generate multiple codes from a single coupon for different distribution channels or customer segments:

General Campaign Code

POST/v1/promotion_codes
curl --request POST \
  --url https://api.framepayments.com/v1/promotion_codes \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "code": "SUMMER50",
  "coupon_id": "cpn_a2b43435cdd944bb8b7ac3ad0ec8b3e2",
  "active": true,
  "max_redemptions": 500,
  "minimum_amount_cents": 5000,
  "minimum_amount_currency": "USD",
  "expires_at": "2025-08-31T23:59:59Z",
  "metadata": {
    "channel": "email_campaign"
  }
}'

First-Time Customer Code

POST/v1/promotion_codes
curl --request POST \
  --url https://api.framepayments.com/v1/promotion_codes \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "code": "WELCOME2025",
  "coupon_id": "cpn_a2b43435cdd944bb8b7ac3ad0ec8b3e2",
  "active": true,
  "first_time_transaction": true,
  "max_redemptions": 200,
  "expires_at": "2025-12-31T23:59:59Z",
  "metadata": {
    "channel": "signup_bonus"
  }
}'

Customer Specific Code

POST/v1/promotion_codes
curl --request POST \
  --url https://api.framepayments.com/v1/promotion_codes \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "code": "WELCOME2025",
  "coupon_id": "cpn_a2b43435cdd944bb8b7ac3ad0ec8b3e2",
  "customer": "cust_1234",
  "active": true,
  "first_time_transaction": false,
  "max_redemptions": 200,
  "expires_at": "2025-12-31T23:59:59Z",
  "metadata": {
    "channel": "signup_bonus"
  }
}'

Promotion Code Features

  • Customer Targeting: Set customer to restrict a code to a specific customer.
  • First-Time Buyers: Enable first_time_transaction to limit usage to new customers only.
  • Independent Limits: Each code can have its own expiration date and usage limits, separate from the parent coupon.

Step 3: Applying Discounts at Checkout

When creating a charge intent, include the promotion codes in the promotion_codes array. Frame will automatically validate eligibility and apply the discounts.

Complete Charge Intent with Promotion Codes

POST/v1/charge_intents
curl --request POST \
  --url https://api.framepayments.com/v1/charge_intents \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "amount": 15000,
  "currency": "USD",
  "description": "Order #12345 - Summer Collection",
  "confirm": true,
  "receipt_email": "customer@example.com",
  "promotion_codes": ["SUMMER50", "WELCOME2025"],
  "customer_data": {
    "name": "John Doe",
    "email": "john.doe@example.com"
  },
  "payment_method_data": {
    "card_number": "4242424242424242",
    "exp_month": "12",
    "exp_year": "26",
    "cvc": "123",
    "type": "card",
    "billing": {
      "line_1": "456 Billing Ave",
      "city": "Los Angeles",
      "country": "US",
      "state": "CA",
      "postal_code": "90001"
    }
  },
  "shipping": {
    "line_1": "123 Main Street",
    "city": "New York",
    "country": "US",
    "state": "NY",
    "postal_code": "10001"
  }
}'

In this example:

  • Original amount: $150.00
  • Discount applied: 20% = $30.00
  • Final amount charged: $120.00

Discount Stacking and Priority

Frame supports applying up to 20 promotion codes per transaction, enabling sophisticated discount strategies.

How Discounts Are Applied

When multiple promotion codes are provided, discounts are applied in the order of their promotion_codes index.

Example: Multiple Discounts

{
  "amount": 20000,
  "promotion_codes": [
    "SUMMER50", // 20% off
    "LOYALTY10" // $5 off
  ]
}

Calculation:

  • Original: $200.00
  • After 20% discount: $160.00
  • After $5 fixed discount: $155.00
  • Final amount: $155.00

Validation and Error Handling

Frame automatically validates promotion codes and returns clear error messages when codes cannot be applied. You can check the eliginility of a promotion code and the application order with the validation endpoint.

Setting Appropriate Limits

Always configure limits to protect your business:

{
  "max_redemptions": 1000, // Prevent unlimited budget exposure
  "minimum_order_amount_cents": 5000, // Ensure profitability per transaction
  "discount_cap_cents": 10000, // Cap maximum discount amount
  "expires_at": "2025-08-31T23:59:59Z" // Clear campaign end date
}

Common Use Cases

Limited Time Flash Sale

Create urgency with a short validity window:

{
  "name": "FLASH_SALE_24H",
  "discount_type": "percentage",
  "discount_value": 30,
  "duration": "once",
  "valid_from": "2025-07-04T00:00:00Z",
  "valid_until": "2025-07-04T23:59:59Z",
  "max_redemptions": 100
}

First-Time Customer Welcome Discount

Incentivize new customer acquisition:

{
  "code": "WELCOME10",
  "first_time_transaction": true,
  "discount_type": "fixed_amount",
  "discount_value": 10,
  "minimum_amount_cents": 0
}

Subscription Annual Discount

Encourage annual commitments:

{
  "name": "ANNUAL_SAVE20",
  "discount_type": "percentage",
  "discount_value": 20,
  "duration": "forever",
  "applicable_to": "specific_products",
  "product_id": "prod_annual_subscription"
}

VIP Customer Personal Code

Reward high-value customers:

{
  "code": "VIP_JOHN_50",
  "customer": "cus_abc123",
  "discount_type": "percentage",
  "discount_value": 50,
  "max_redemptions": 1,
  "expires_at": "2025-12-31T23:59:59Z"
}

Cart Abandonment Recovery

Re-engage customers who didn't complete checkout:

{
  "name": "COMEBACK_15",
  "discount_type": "percentage",
  "discount_value": 15,
  "duration": "once",
  "valid_from": "2025-06-01T00:00:00Z",
  "valid_until": "2025-06-30T23:59:59Z",
  "metadata": {
    "campaign": "cart_recovery",
    "trigger": "abandoned_7_days"
  }
}

Real-Time Code Validation

Validate promotion codes as customers enter them (before submitting payment):

GET/v1/promotion_codes/:code
curl --request GET \
  --url https://api.framepayments.com/v1/promotion_codes/:code \
  --header 'Authorization: Bearer YOUR_API_KEY'

This allows you to:

  • Show discount amount before payment
  • Display error messages immediately
  • Calculate final amount in real-time
  • Improve customer experience

Quick Reference

API Endpoints

ActionMethodEndpoint
Create CouponPOST/v1/coupons
Update CouponPATCH/v1/coupons/:id
List CouponsGET/v1/coupons
Get CouponGET/v1/coupons/:id
Create Promotion CodePOST/v1/promotion_codes
Update Promotion CodePATCH/v1/promotion_codes/:id
List Promotion CodesGET/v1/promotion_codes
Get Promotion CodeGET/v1/promotion_codes/:id
Create Charge IntentPOST/v1/charge_intents

Key Concepts

  • Coupon: Reusable discount template that defines rules and restrictions
  • Promotion Code: Customer-facing code generated from a coupon
  • Stackable Discounts: Up to 20 codes can be applied per transaction
  • Duration Types: once (single use), repeating (multiple cycles), forever (indefinite)
  • Discount Types: percentage (e.g., 20%) or fixed_amount (e.g., $10)

Status Values

Coupon Statuses:

  • active - Coupon can be used
  • inactive - Temporarily disabled
  • archived - Preserved but not usable
  • deleted - Soft deleted

Promotion Code Flags:

  • is_expired - Past expiration date
  • is_maxed_out - Reached redemption limit
  • is_redeemable - Currently usable
  • is_customer_specific - Restricted to one customer

Additional Resources

For detailed technical specifications and parameter references: