Skip to main content

Perk Charges & Redemption API

Track and manage per-NFT usage charges for claimed perks. When a customer claims a perk NFT, it starts with a set number of charges. Your backend calls this API to decrement charges each time the perk is redeemed (e.g., scanning a QR code, presenting at checkout).

Authentication

These endpoints use HMAC signature authentication with your existing Brand ID and Security Key from the Partner Portal. No additional API keys required.

Overview

Pattern: Brand-authenticated charge management

  1. Customer claims a perk NFT (charges initialized automatically)
  2. Customer presents perk at your business (QR code, membership card, etc.)
  3. Your backend calls POST /redeem-perk with HMAC signature
  4. Charges decrement; remaining count returned
  5. NFT metadata updates to reflect current charge state

Use Cases:

  • Multi-visit coffee cards (10 charges = 10 coffees)
  • Monthly subscription perks (12 charges = 12 months)
  • Event access passes (3 charges = 3 events)
  • Unlimited-use membership cards (0 charges = unlimited)

Base URL

https://relayer.rsnc.network

Authentication

All perk charges endpoints require HMAC signature authentication using three headers:

X-Resonance-Brand-Id: 0xYourBrandWalletAddress
X-Resonance-Signature: <HMAC-SHA256 signature>
X-Resonance-Timestamp: <Unix timestamp in seconds>

How HMAC Signing Works

  1. Get your Brand ID (wallet address) and Security Key from Partner Portal → Settings → Profile
  2. Construct the signing payload: BrandId|RequestBody|Timestamp
  3. Compute HMAC-SHA256(payload, SecurityKey) and send as hex in the signature header
Timestamp Window

Signatures are valid for 5 minutes. Requests with timestamps older than 5 minutes are rejected.

Signing Example

# Your credentials (from Partner Portal → Settings → Profile)
BRAND_ID="0xYourBrandWalletAddress"
SECURITY_KEY="your-64-char-hex-security-key"

# Request details
TIMESTAMP=$(date +%s)
BODY='{"token_id":42,"collection_id":7,"charges_to_use":1}'

# Compute HMAC-SHA256
PAYLOAD="${BRAND_ID}|${BODY}|${TIMESTAMP}"
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECURITY_KEY" | awk '{print $2}')

Signing for GET Requests

For GET requests (no body), the payload is: BrandId||Timestamp

PAYLOAD="${BRAND_ID}||${TIMESTAMP}"
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECURITY_KEY" | awk '{print $2}')

Endpoints

POST /redeem-perk

Decrement charges on a specific perk NFT token. Call this each time a customer redeems their perk at your business.

Headers:

Content-Type: application/json
X-Resonance-Brand-Id: 0xYourBrandWalletAddress
X-Resonance-Signature: <HMAC-SHA256 hex>
X-Resonance-Timestamp: <Unix seconds>

Request Body:

{
"token_id": 42,
"collection_id": 7,
"charges_to_use": 1,
"notes": "Redeemed at downtown location"
}

Parameters:

FieldTypeRequiredDescription
token_idintegerYesThe NFT token ID (from the customer's wallet)
collection_idintegerYesYour perk collection ID
charges_to_useintegerNoNumber of charges to deduct (default: 1)
notesstringNoOptional note for audit log (e.g., location, staff ID)

Success Response (200):

{
"success": true,
"token_id": 42,
"collection_id": 7,
"total_charges": 10,
"used_charges": 3,
"remaining": 7
}

No Charges Remaining (409):

{
"error": "No charges remaining",
"token_id": 42,
"collection_id": 7,
"total_charges": 10,
"used_charges": 10,
"remaining": 0
}

Unlimited Charges: When total_charges is 0, the perk has unlimited uses. The response returns "remaining": "unlimited" and redemptions always succeed.

curl Example

BRAND_ID="0xYourBrandWalletAddress"
SECURITY_KEY="your-64-char-hex-security-key"
TIMESTAMP=$(date +%s)
BODY='{"token_id":42,"collection_id":7,"charges_to_use":1,"notes":"Downtown store"}'

PAYLOAD="${BRAND_ID}|${BODY}|${TIMESTAMP}"
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECURITY_KEY" | awk '{print $2}')

curl -X POST https://relayer.rsnc.network/redeem-perk \
-H "Content-Type: application/json" \
-H "X-Resonance-Brand-Id: ${BRAND_ID}" \
-H "X-Resonance-Signature: ${SIGNATURE}" \
-H "X-Resonance-Timestamp: ${TIMESTAMP}" \
-d "${BODY}"

GET /check-perk-status

Query the current charge status for a specific perk NFT token. Use this to check whether a perk is still valid before redeeming.

Headers:

X-Resonance-Brand-Id: 0xYourBrandWalletAddress
X-Resonance-Signature: <HMAC-SHA256 hex>
X-Resonance-Timestamp: <Unix seconds>

Query Parameters:

ParameterTypeRequiredDescription
token_idintegerYesThe NFT token ID
collection_idintegerYesYour perk collection ID

Success Response (200):

{
"token_id": 42,
"collection_id": 7,
"total_charges": 10,
"used_charges": 3,
"remaining": 7,
"last_redeemed_at": "2025-06-15T14:30:00Z"
}

Never-redeemed token (200):

{
"token_id": 42,
"collection_id": 7,
"total_charges": 10,
"used_charges": 0,
"remaining": 10,
"last_redeemed_at": null
}

curl Example

BRAND_ID="0xYourBrandWalletAddress"
SECURITY_KEY="your-64-char-hex-security-key"
TIMESTAMP=$(date +%s)

PAYLOAD="${BRAND_ID}||${TIMESTAMP}"
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECURITY_KEY" | awk '{print $2}')

curl -G "https://relayer.rsnc.network/check-perk-status" \
--data-urlencode "token_id=42" \
--data-urlencode "collection_id=7" \
-H "X-Resonance-Brand-Id: ${BRAND_ID}" \
-H "X-Resonance-Signature: ${SIGNATURE}" \
-H "X-Resonance-Timestamp: ${TIMESTAMP}"

GET /list-perk-holders

List all holders and their charge status for one of your perk collections. Useful for dashboards showing who has claimed your perks and how many charges remain.

Headers:

X-Resonance-Brand-Id: 0xYourBrandWalletAddress
X-Resonance-Signature: <HMAC-SHA256 hex>
X-Resonance-Timestamp: <Unix seconds>

Query Parameters:

ParameterTypeRequiredDescription
collection_idintegerYesYour perk collection ID

Success Response (200):

{
"collection_id": 7,
"charges_per_nft": 10,
"total_tokens": 3,
"claimants": [
{
"address": "0xCustomer1Address...",
"claim_count": 2
},
{
"address": "0xCustomer2Address...",
"claim_count": 1
}
],
"holders": [
{
"token_id": 42,
"total_charges": 10,
"used_charges": 3,
"remaining": 7,
"last_redeemed_at": "2025-06-15T14:30:00Z",
"minted_at": "2025-06-01T10:00:00Z"
},
{
"token_id": 43,
"total_charges": 10,
"used_charges": 0,
"remaining": 10,
"last_redeemed_at": null,
"minted_at": "2025-06-02T12:00:00Z"
}
]
}

curl Example

BRAND_ID="0xYourBrandWalletAddress"
SECURITY_KEY="your-64-char-hex-security-key"
TIMESTAMP=$(date +%s)

PAYLOAD="${BRAND_ID}||${TIMESTAMP}"
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECURITY_KEY" | awk '{print $2}')

curl -G "https://relayer.rsnc.network/list-perk-holders" \
--data-urlencode "collection_id=7" \
-H "X-Resonance-Brand-Id: ${BRAND_ID}" \
-H "X-Resonance-Signature: ${SIGNATURE}" \
-H "X-Resonance-Timestamp: ${TIMESTAMP}"

Setting Charges Per Perk

When creating a perk in the Partner Portal, set the "Uses per perk" field:

ValueBehavior
1Single-use (default). Perk can be redeemed once.
NMulti-use. Each NFT gets exactly N redemptions.
0Unlimited. Perk can be redeemed any number of times.

This value is stored as charges_per_nft on the collection. When a customer claims the perk, a charge tracking row is automatically created with the correct total.


NFT Metadata Integration

Charge state is reflected in the NFT's ERC-721 metadata (visible on block explorers, wallets, and marketplaces):

{
"name": "Coffee Card #42",
"description": "10-visit coffee card from Bean Co.",
"image": "https://...",
"attributes": [
{ "trait_type": "Collection", "value": "Coffee Card" },
{ "trait_type": "Brand", "value": "Bean Co." },
{ "trait_type": "Total Charges", "value": "10" },
{ "trait_type": "Charges Used", "value": "3" },
{ "trait_type": "Charges Remaining", "value": "7" }
]
}
Cache Behavior

NFT metadata is cached for up to 5 minutes. After redeeming a charge, the updated metadata may take a few minutes to appear on block explorers.


Error Codes

StatusMeaningDescription
200SuccessOperation completed
400Bad RequestMissing or invalid parameters
401UnauthorizedHMAC signature invalid, expired, or missing Brand ID
403ForbiddenBrand does not own this collection
404Not FoundCollection not found
409ConflictNo charges remaining on this token
500Server ErrorInternal error

Integration Patterns

Point-of-Sale Redemption

Your POS system verifies and redeems a perk when a customer presents it:

# 1. Customer presents perk (token_id from their wallet/QR code)
# 2. Check if perk is valid
curl -G "https://relayer.rsnc.network/check-perk-status" \
--data-urlencode "token_id=42" \
--data-urlencode "collection_id=7" \
-H "X-Resonance-Brand-Id: ${BRAND_ID}" \
-H "X-Resonance-Signature: ${SIGNATURE}" \
-H "X-Resonance-Timestamp: ${TIMESTAMP}"

# 3. If remaining > 0, redeem
curl -X POST "https://relayer.rsnc.network/redeem-perk" \
-H "Content-Type: application/json" \
-H "X-Resonance-Brand-Id: ${BRAND_ID}" \
-H "X-Resonance-Signature: ${SIGNATURE}" \
-H "X-Resonance-Timestamp: ${TIMESTAMP}" \
-d '{"token_id":42,"collection_id":7,"charges_to_use":1,"notes":"Store #5, register 2"}'

Webhook-Triggered Redemption

Automatically redeem when an external event occurs (e.g., subscription renewal):

# Called by your subscription webhook handler
curl -X POST "https://relayer.rsnc.network/redeem-perk" \
-H "Content-Type: application/json" \
-H "X-Resonance-Brand-Id: ${BRAND_ID}" \
-H "X-Resonance-Signature: ${SIGNATURE}" \
-H "X-Resonance-Timestamp: ${TIMESTAMP}" \
-d '{"token_id":42,"collection_id":7,"charges_to_use":1,"notes":"Monthly subscription renewal - July 2025"}'

Dashboard: List All Holders

Build an internal dashboard showing all perk holders and their usage:

curl -G "https://relayer.rsnc.network/list-perk-holders" \
--data-urlencode "collection_id=7" \
-H "X-Resonance-Brand-Id: ${BRAND_ID}" \
-H "X-Resonance-Signature: ${SIGNATURE}" \
-H "X-Resonance-Timestamp: ${TIMESTAMP}"

Security

Ownership Verification

All endpoints verify that your Brand ID (wallet address) matches the creator_address on the perk collection. You can only manage charges for collections you created.

Audit Trail

Every redemption is logged in an immutable perk_redemption_log with:

  • Token ID and collection ID
  • Brand ID that performed the redemption
  • Number of charges used
  • Timestamp
  • Optional notes

Signature Replay Protection

  • Timestamps must be within 5 minutes of server time
  • Each signature is unique to the request body and timestamp

Best Practices

  1. Check before redeeming - Call /check-perk-status before /redeem-perk to show the customer their remaining charges and avoid unnecessary 409 errors
  2. Include notes - Add location, staff ID, or order number to the notes field for audit tracking
  3. Handle 409 gracefully - When charges are exhausted, show the customer a clear "perk fully redeemed" message
  4. Use unlimited (0) for memberships - Set charges to 0 for ongoing membership cards that never expire
  5. Monitor with list-perk-holders - Periodically check holder status to identify customers nearing exhaustion for re-engagement campaigns


Need Help?