The SuperPay Checkout API ranks the top 3 credit cards by reward rate for a given purchase. It powers the <script>-tag widget that turns your checkout into an instant top-3 cards prompt (stacked, tappable rows, best first) — and it can be called server-to-server too.
Every request needs a merchant API key issued by SuperPay. Send it in either of two headers:
Authorization: Bearer sp_live_xxxxxxxx_…
X-SuperPay-Key: sp_live_xxxxxxxx_…
Keys are sp_live_ + 8 hex characters + _ + 48 hex characters. Treat keys like passwords: never commit them to client-side source control. The drop-in widget script is the one exception — it's designed to ship the key in the page so a browser can call /v1/recommend directly.
When SuperPay issues your key we register the exact origins (e.g. https://shop.example.com) you'll mount the widget on. Browser requests from any other origin are rejected with HTTP 403 ORIGIN_NOT_ALLOWED. Server-to-server calls (no Origin header) are not subject to this check — the API key alone authorizes them.
Returns the top 3 cards from our ~320-card catalog for the requested category in top_cards (ordered best first), each with an estimated reward in cents (informational — issued by the shopper's card issuer, not by SuperPay), and a SuperPay signup_url the shopper can tap to install the SuperPay app and get the same recommendations everywhere they shop.
top_card and lighter alternates[] fields are still populated for backwards compatibility but will be removed one release after this one ships. Please migrate to top_cards[] — it carries the full data for every rank, including the previously-best card at top_cards[0].
| Field | Type | Required | Notes |
|---|---|---|---|
amount | number | yes | USD, e.g. 87.45 |
mcc | string | preferred | ISO 18245 4-digit code. Takes precedence over category when both are supplied. |
category | string | fallback | Used only when MCC is missing or unmapped. One of dining, groceries, gas, travel, entertainment, online_shopping, streaming, drugstores, home_improvement, transit, shopping, other |
merchant_name | string | recommended | Display name, e.g. "Whole Foods Market" |
curl -X POST https://www.superpayrewards.com/v1/recommend \
-H "Authorization: Bearer sp_live_…" \
-H "Content-Type: application/json" \
-d '{
"amount": 87.45,
"mcc": "5411",
"merchant_name": "Whole Foods Market"
}'
{
"recommendation_id": "9f8…",
"anonymous": true,
"category": "groceries",
"amount_cents": 8745,
"top_cards": [
{
"source": "catalog",
"rank": 1,
"id": "amex_blue_cash_preferred",
"name": "Blue Cash Preferred® Card from American Express",
"issuer": "American Express",
"network": "American Express",
"reward_rate": 6,
"reward_type": "cashback",
"estimated_reward_cents": 524,
"estimated_reward_display": "$5.24",
"reason": "6% on groceries",
"image_url": "https://…",
"apply_url": "https://…"
},
{ "rank": 2, "id": "amex_gold", … },
{ "rank": 3, "id": "citi_custom_cash", … }
],
"top_card": { /* DEPRECATED — same as top_cards[0]. Will be removed one release after this one. */ },
"alternates": [ /* DEPRECATED — top_cards[1..] in lighter shape. Will be removed one release after this one. */ ],
"signup_url": "https://www.superpayrewards.com/r/install/checkout_widget?utm_source=merchant&utm_medium=checkout_widget",
"display": {
"headline": "Top 3 cards for this purchase",
"subline": "Top pick: Blue Cash Preferred · 6% back"
}
}
Paste this into your checkout page. Render the <div> wherever you want the top-3 cards widget to appear and load /v1/widget.js once, anywhere on the page:
<div data-superpay-recommend
data-amount="87.45"
data-mcc="5411"
data-merchant="Whole Foods Market"
data-theme="light"
data-superpay-effective-cost-target="#sp-effective-cost"></div>
<!-- Optional: empty target the widget fills with
"Effective cost with SuperPay: $X.XX — after $Y.YY rewards".
Place under your Pay / Place Order button. -->
<div id="sp-effective-cost"></div>
<script src="https://www.superpayrewards.com/v1/widget.js" data-key="sp_live_…" async></script>
The widget renders a small card up to 360px wide containing the top 3 recommended cards as stacked rows, themes light/dark via data-theme, and never breaks the merchant's checkout (it silently no-ops on any error). The CORS-allowed JS calls /v1/recommend directly from the browser. The SuperPay-branded header is a single tap target pointing at signup_url so a shopper without SuperPay can install the app; each card row is its own tap target pointing at that card's apply_url. Rewards themselves are always awarded by the shopper's card issuer — SuperPay does not hold funds or pay out rewards.
Pass an extra data-superpay-effective-cost-target="<css-selector>" on the mount <div> and place an empty target element (typically directly under your Pay / Place Order button). The widget will fill that element with a single muted line: "Effective cost with SuperPay: $X.XX — after $Y.YY rewards". The line is strictly gated so it never lies to a shopper — it renders only when the top pick is a cashback card with a positive estimated reward, a known cart total, and the resulting effective cost is non-negative (rewards never shown as exceeding the order total). Points/miles cards, $0 reward estimates, missing amounts, or a negative effective cost suppress the line silently.
| Status | Code | Meaning |
|---|---|---|
| 400 | INVALID_AMOUNT | amount missing or out of range |
| 401 | MISSING_API_KEY / INVALID_API_KEY / API_KEY_REVOKED | auth failed |
| 200 | top_cards: [] | no catalog card matches the requested category and merchant — the widget hides itself silently. Replaced the legacy 404 NO_RECOMMENDATION response in Task #739. |
| 429 | RATE_LIMITED | over 300 requests per minute on this key |
| 500 | INTERNAL_ERROR | SuperPay-side failure — safe to retry |
Rate limits are per API key. Headers X-RateLimit-Limit, X-RateLimit-Remaining, and Retry-After are set on every response.
The Bank Partner API is a private B2B surface for financial institutions. It lets your engineering team surface card recommendations from your own issued portfolio at checkout — only cards your institution has authorized appear in results. Requires a sp_bank_ key issued after your institution's application is reviewed.
sp_bank_) is available immediately on the Bank Partner portal.
Bank keys use the prefix sp_bank_ and are sent the same way as merchant keys:
Authorization: Bearer sp_bank_xxxxxxxx_…
Returns the best card(s) from your authorized portfolio for a given purchase. Same request shape as /v1/recommend, plus an optional card_product_ids array to scope results to a subset of your portfolio.
| Field | Type | Notes |
|---|---|---|
amount | number | Required. USD purchase amount. |
mcc | string | Preferred. 4-digit ISO 18245 code. |
merchant_name | string | Recommended display name. |
card_product_ids | string[] | Optional. Restrict results to this subset of your portfolio (e.g. a specific customer segment). Omit = all authorized cards. |
curl -X POST https://www.superpayrewards.com/v1/bank/recommend \
-H "Authorization: Bearer sp_bank_…" \
-H "Content-Type: application/json" \
-d '{
"amount": 87.45,
"mcc": "5411",
"merchant_name": "Whole Foods Market",
"card_product_ids": ["amex_gold", "chase_sapphire_preferred"]
}'
const res = await fetch('https://www.superpayrewards.com/v1/bank/recommend', {
method: 'POST',
headers: {
'Authorization': 'Bearer sp_bank_…',
'Content-Type': 'application/json',
},
body: JSON.stringify({ amount: 87.45, mcc: '5411', card_product_ids: ['amex_gold'] }),
});
const { top_cards, category, portfolio_scoped } = await res.json();
{
"recommendation_id": "9f8…",
"category": "groceries",
"amount_cents": 8745,
"portfolio_scoped": true,
"top_cards": [
{
"rank": 1, "id": "amex_gold",
"name": "American Express Gold Card",
"issuer": "American Express",
"reward_rate": 4, "reward_type": "points",
"estimated_reward_cents": 349,
"reason": "4% on groceries"
}
]
}
Analyzes a set of card product IDs against a monthly spend profile and returns per-category winner allocation, gap analysis vs. the broader market, and projected annual rewards per card.
| Field | Type | Notes |
|---|---|---|
card_product_ids | string[] | Required. SuperPay card product IDs to analyze. |
spend_profile | object | Required. Category → monthly USD spend. E.g. {"groceries":800,"dining":400}. Keys: groceries, dining, gas, travel, entertainment, streaming, other. Values: positive finite USD amounts. Omitting this field returns 400 MISSING_SPEND_PROFILE. |
curl -X POST https://www.superpayrewards.com/v1/bank/portfolio \
-H "Authorization: Bearer sp_bank_…" \
-H "Content-Type: application/json" \
-d '{
"card_product_ids": ["amex_gold", "chase_sapphire_preferred", "citi_double_cash"],
"spend_profile": { "groceries": 800, "dining": 400, "travel": 600 }
}'
import requests
r = requests.post(
'https://www.superpayrewards.com/v1/bank/portfolio',
headers={'Authorization': 'Bearer sp_bank_…'},
json={
'card_product_ids': ['amex_gold', 'chase_sapphire_preferred'],
'spend_profile': {'groceries': 800, 'dining': 400},
}
)
data = r.json()
for cat, winner in data['optimal_allocation'].items():
print(f"{cat}: {winner['card_name']} @ {winner['reward_rate']}%")
{
"analysis_id": "…",
"portfolio_card_count": 3,
"cards": [
{
"id": "amex_gold", "name": "American Express Gold Card",
"found_in_catalog": true, "best_category": "dining",
"best_rate": 4, "projected_annual_reward_cents": 57600
}
],
"optimal_allocation": {
"groceries": { "card_id": "amex_gold", "card_name": "American Express Gold Card", "reward_rate": 4, "estimated_monthly_reward_cents": 3200 },
"dining": { "card_id": "amex_gold", "reward_rate": 4, "estimated_monthly_reward_cents": 1600 },
"travel": { "card_id": "chase_sapphire_preferred", "reward_rate": 3, "estimated_monthly_reward_cents": 1800 }
},
"summary": {
"total_monthly_portfolio_reward_cents": 6600,
"total_projected_annual_reward_cents": 79200,
"total_monthly_gap_cents": 1200,
"coverage_rate": 1.0
},
"top_gaps": [ … ],
"by_category": [ … ]
}
| Status | Code | Meaning |
|---|---|---|
| 400 | NO_CARDS_IN_PORTFOLIO | The requested card_product_ids have no cards with a bonus in the requested category. Widen the portfolio or try a different category. |
| 400 | MISSING_CARD_IDS | card_product_ids missing or empty on /v1/bank/portfolio. |
| 400 | MISSING_SPEND_PROFILE | spend_profile missing on /v1/bank/portfolio. Must be a non-empty object of category → monthly USD spend. |
| 400 | INVALID_SPEND_PROFILE | spend_profile contains non-finite values (Infinity, NaN, or negative). All spend values must be positive finite numbers. |
| 401 | MISSING_API_KEY / INVALID_API_KEY | Auth failed — check your sp_bank_ key. |
| 403 | ACCESS_DENIED | Your key's access level does not include this endpoint. |
| 403 | ORIGIN_NOT_ALLOWED | The Origin header is not in your key's allowed origins list. Remove the Origin header for server-to-server calls, or contact us to add the origin. |
| 429 | RATE_LIMITED | Over 300 req/min on this key. |
| 500 | INTERNAL_ERROR | SuperPay-side failure — safe to retry with exponential back-off. |
Read the full Bank Partner Guide (PDF) for onboarding steps, portfolio ID lookup, and integration best practices.
#00C896#0A1628SuperPay issues two types of API keys:
| Key type | Prefix | How to get | Rate limit | Behavior |
|---|---|---|---|---|
| Sandbox | sp_test_ | Email hello@superpayrewards.com | 300 req/min | Returns static mock recommendations; no analytics tracked. Use for development & testing. |
| Live | sp_live_ | Apply on the Developers page | 300 req/min | Returns real catalog recommendations; usage logged and visible in your merchant dashboard. |
Sandbox keys are available immediately on request. Live keys require a brief application review (typically < 1 business day) to ensure origin allowlists and integration quality.
Ready to integrate? Apply for a live API key →
Submit your business name, contact email, store origins, and a brief description of your integration. We'll verify your email and review your application — you'll receive your sp_live_… key via email once approved, typically within 1 business day.
Need to rotate a lost key or update your allowed origins? Email hello@superpayrewards.com.