Resources

Developer docs

Integration guide for POS systems connecting checkout validation, redemption recording, and void handling to SponsorPay.

Authentication

API keys

All POS endpoints use an API key in the request header. No login session is needed. The key is tied to your store — you never send a storeId.

Generate keys in the store portal under API Keys. The raw key is shown only once on creation — store it securely. Send it on every POS request:

x-api-key: YOUR_KEY

401 on any call

Means the key is missing, wrong, or deactivated. Check the header name and value first. If a key was regenerated, the old one is immediately invalidated.

Response format

Always check ok, not the HTTP status

Every response includes ok: true on success or ok: false on failure. Redemption endpoints return HTTP 200 even on business failures — an invalid coupon, a wrong phone number, and an empty wallet all come back as HTTP 200 with ok: false. Always check the ok field.

Success

{ "ok": true, ...data }

Failure

{ "ok": false, "error": "..." }

Decimal / money values are returned as strings ("30.00"). Dates are UTC ISO strings.

The checkout flow

3 steps at the register

01

Scan the barcode

GET /api/store/barcode/:code

Call this when the cashier scans a barcode. It's read-only — nothing is charged. Returns the coupon type, whether it's active, the POS discount ID to apply, and the discount percentages.

02

Apply in your POS

Use posDiscountId

Take the posDiscountId from the scan response and use it to auto-apply the matching promotion already configured in your POS system. Your POS handles item and category eligibility.

03

Record the redemption

POST /api/store/coupon/redeem

After the sale is finalized, call redeem with the sale totals. This commits the redemption, charges the sponsor's wallet, and credits your store wallet. Save the redemption ID in case you need to void.

posDiscountId — the key to automation

When a store creates a Discount Option, they enter the ID of a promotion already configured in their POS (a Clover Promotion, Square Discount, Toast Applied Discount, etc.). That promotion has all item and category rules baked in. When you scan a barcode and get back posDiscountId, auto-apply that promotion in your POS. Your POS handles eligibility. SponsorPay only sees the final dollar amounts you report.

Endpoint

Scan a barcode

GET /api/store/barcode/:code

Call this when the cashier scans a barcode or types in a code. Safe to call multiple times — nothing is charged. Returns the type (coupon or giftCard), whether the item is currently redeemable, and the data your POS needs to apply the discount.

Response — active coupon

{
  "ok": true,
  "found": true,
  "type": "coupon",
  "active": true,
  "data": {
    "couponId": 88,
    "code": "ABC123",
    "posDiscountId": "CLOVER-PROMO-47",
    "totalPercent": 30,
    "sponsorPercent": 15,
    "storePercent": 15,
    "requirePhone": false,
    "phoneLast3": null,
    "maxAmountDiscountApplies": null,
    "maxDiscountThisSale": null,
    "sponsorRemaining": null
  }
}

Response — active gift card

{
  "ok": true,
  "found": true,
  "type": "giftCard",
  "active": true,
  "data": {
    "giftCardId": 55,
    "code": "GC-123",
    "amount": 25.00,
    "requirePhone": false,
    "phoneLast3": null
  }
}

amount is the remaining balance — the maximum redeemable.

Response fields

FieldDescription
posDiscountIdID of the matching promotion in your POS. Auto-apply this. null if not configured.
totalPercentTotal discount % to apply at checkout.
sponsorPercent / storePercentHow the % is split. For reporting only — apply totalPercent.
requirePhoneIf true, prompt the customer for their phone number before completing the sale.
phoneLast3Last 3 digits of the registered phone. Show in your UI so the customer can confirm it's theirs. null if none on file.
maxAmountDiscountAppliesCap on how much of the sale the discount can apply to. Limit your totalAmountDiscountApplies to this. null = no cap.
maxDiscountThisSaleCap on total discount dollar amount for this sale. null = no cap.
sponsorRemainingRemaining sponsor budget on this coupon. null = no cap.

Response — coupon not redeemable

{
  "ok": true,
  "found": true,
  "type": "coupon",
  "active": false,
  "reason": "COUPON_NOT_ACTIVE"
}

Reason codes

ReasonMeaning
COUPON_NOT_ACTIVEAlready used or voided
COUPON_REDEMPTION_LIMIT_REACHEDUsed the max number of times
COUPON_AMOUNT_LIMIT_REACHEDSponsor budget exhausted
COUPON_SALE_LIMIT_REACHEDCumulative sale amount limit reached
COUPON_DISCOUNT_LIMIT_REACHEDCumulative discount dollar limit reached
COUPON_STORE_LIMIT_REACHEDSingle-use per store; already used here
DISCOUNT_NOT_ACTIVECampaign not active
DISCOUNT_EXPIREDCampaign expired
DISCOUNT_OPTION_INACTIVEStore's discount option is off or not approved
DISCOUNT_OPTION_EXPIREDStore's discount option expired
SPONSOR_NOT_ACTIVESponsor account inactive
STORE_INACTIVEYour store account is inactive

Endpoint

Record a coupon redemption

POST /api/store/coupon/redeem

Call this after the sale is finalized in your POS. This commits the redemption, charges the sponsor's wallet, and credits your store wallet. Save the redemption.id from the response — you'll need it to void.

Request body

{
  "code": "ABC123",
  "saleId": "TXN-48291",
  "totalSaleAmount": 100.00,
  "totalItems": 3,
  "totalAmountDiscountApplies": 100.00,
  "totalDiscount": 30.00,
  "roundedDiscount": false,
  "phone": "2125551111",
  "storeDiscountAdjustmentPercent": 0,
  "storeDiscountAdjustmentReason": null,
  "registerId": "REG-1",
  "cashierId": "CASHIER-7",
  "metadata1": null,
  "metadata2": null,
  "metadata3": null
}

Success response

{
  "ok": true,
  "redemption": {
    "id": 1001,
    "status": "COMMITTED",
    "saleId": "TXN-48291",
    "discountAmount": "30.00",
    "sponsorDiscountAmount": "15.00",
    "storeDiscountAmount": "15.00",
    "createdAt": "2026-05-07T20:02:04.237Z"
  },
  "totals": {
    "discountAmount": "30.00",
    "sponsorDiscountAmount": "15.00",
    "storeDiscountAmount": "15.00"
  }
}

Save the redemption ID

Store redemption.id in your POS transaction record. You need it if the cashier voids the sale.

Request fields

FieldTypeRequiredNotes
codestringYesThe scanned coupon barcode
saleIdstringYesYour POS's unique sale ID. Used to prevent duplicate redemptions.
totalSaleAmountnumberYesFull sale total before discount
totalItemsintegerYesNumber of items in the sale
totalAmountDiscountAppliesnumberYesThe portion of the sale your POS promotion applied the discount to. Do not exceed maxAmountDiscountApplies from the scan.
totalDiscountnumberYesActual total discount dollar amount your POS applied. Server validates this matches its calculation.
roundedDiscountbooleanYestrue if your POS rounded the discount to a whole dollar. Affects server match tolerance. Default false.
phonestringNo10 digits. Required when requirePhone: true. Must match the registered phone.
storeDiscountAdjustmentPercentintegerNoNegative integer only. Reduces the store's % contribution (e.g. -5). Default 0.
storeDiscountAdjustmentReasonstringNoRequired when adjustment is non-zero. Values: "PAID_CC" | "OTHER"
registerIdstringNoYour terminal/register ID. For reporting.
cashierIdstringNoCashier ID. For reporting.
metadata1–3stringNoFree-form reference fields.

Unknown fields are rejected.

Error responses (ok: false, HTTP 200)

Error messageMeaning
Coupon not found.Barcode not valid at this store
Coupon is not active.Coupon already used or voided
Discount is not active. / Discount is expired.Campaign issue on sponsor side
Discount option is not active. / ...expired. / ...not approved.Store option issue
Phone is required.requirePhone was true; phone field not sent
Phone does not match.Wrong phone number provided
Duplicate sale.saleId already redeemed at this store — usually means it worked first time
Coupon redemption limit reached.Too many uses
Coupon amount limit reached.Sponsor budget exhausted
Coupon total sale limit reached.Cumulative sale cap hit
Coupon total discount limit reached.Cumulative discount cap hit
Coupon has already been used at this store.Single-use per store
Discount redemption limit reached.Campaign-level count cap hit
Discount amount limit reached.Campaign-level dollar cap hit
Total discount does not match.totalDiscount doesn't match server calculation
Insufficient funds.Sponsor wallet is empty

Endpoint

Void a redemption

POST /api/store/redemption/discount/:id/void

Call this when the cashier voids the sale in your POS. Must be done within 24 hours. The sponsor's wallet is refunded and the store's pending wallet credit is cancelled.

Request

POST /api/store/redemption/discount/1001/void

{ "reason": "Sale voided" }

Path param id is the redemption.id from the redeem response.

Success response

{
  "ok": true,
  "redemption": {
    "id": 1001,
    "status": "VOIDED",
    "voidedAt": "2026-05-07T21:30:00.000Z",
    "voidReason": "Sale voided"
  }
}

Error responses

ErrorMeaning
Discount redemption not found.ID doesn't exist or belongs to a different store
Only committed redemptions can be voided.Already voided or failed
Redemption can only be voided within 24 hours.Void window has closed
Redemption can no longer be voided.Wallet credit already settled

Endpoint

Redeem a gift card

POST /api/store/giftCard/redeem

Gift cards work like coupons but carry a dollar balance instead of a percentage. Scan the gift card barcode first with GET /api/store/barcode/:code to confirm it's active and check the remaining balance, then call this endpoint after the sale is finalized. The redemption amount must not exceed the remaining balance from the scan.

Request body

{
  "code": "GC-123",
  "amount": 20.00,
  "saleId": "TXN-48292",
  "phone": "2125551111",
  "registerId": "REG-1",
  "cashierId": "CASHIER-7"
}

Success response

{
  "ok": true,
  "redemption": {
    "id": 901,
    "status": "COMMITTED",
    "amount": "20",
    "saleId": "TXN-48292",
    "createdAt": "2026-05-07T20:02:04.237Z"
  },
  "totals": { "amount": "20" }
}

Request fields

FieldRequiredNotes
codeYesGift card code
amountYesAmount to redeem. Min 0.01. Must not exceed remaining balance from scan.
saleIdYesUnique sale ID for duplicate prevention
phoneNo10 digits. Required when requirePhone: true.
registerIdNoFor reporting
cashierIdNoFor reporting

Unknown fields are rejected.

Error responses

Error messageMeaning
Gift card not found.Code not valid at this store
Gift card is not active.Already fully redeemed or voided
Gift card is expired.Past expiry date
Phone is required. / Phone does not match.Phone verification failed
Duplicate sale.saleId already used
Gift card amount limit reached.Requested amount exceeds remaining balance
Insufficient funds.Sponsor wallet empty

Retry safety

Handling timeouts

If a redeem request times out with no response, retry with the exact same saleId.

Original succeeded

Retry returns "Duplicate sale." — meaning it worked the first time. Treat this as a successful redemption.

Original truly failed

The retry processes normally as if it's a new request.

Never retry ok: false errors

Business errors (invalid coupon, wrong phone, empty wallet) are deterministic. Retrying them will not change the outcome.

Automation checklist

What your POS handles

Barcode scanned

Call GET /api/store/barcode/:code

Coupon active

Look up posDiscountId → apply that promotion in POS

requirePhone: true

Show phone entry prompt to customer (not cashier)

Eligible items determined

Your POS promotion handles this; report result as totalAmountDiscountApplies

Sale complete

Call POST /api/store/coupon/redeem or POST /api/store/giftCard/redeem

Sale voided

Call POST /api/store/redemption/discount/:id/void

ok: false on redeem

Show error to customer; do not apply discount; do not retry

Need help?

Contact us for API keys and POS setup

For endpoint questions, API key provisioning, or help matching the integration to your specific POS system, reach out and we'll get you set up.

Contact SponsorPay