POST/tenants/{tenantId}/transactions/evaluate

The earn endpoint. Evaluates a basket against all active campaigns — awarding points and/or issuing tangible rewards (coupons, gift cards, free items, discount vouchers) for each match. Members are auto-created on first call — no pre-registration needed. Fully idempotent on transactionRef: safe to retry on network failure.

Idempotent — calling evaluate twice with the same transactionRef returns the original result, never a duplicate award. Safe to retry on network errors.

Path Parameters

tenantIdstring uuid
required
Your tenant UUID, returned when you registered.

Request Body

transactionRefstring
required
Your unique reference for this transaction — typically your POS basket ID or receipt number. Used for idempotency.
memberRefstring
required
Your customer's identifier — hashed MSISDN, loyalty card number, or app user ID. Member is auto-created on first call.
amountinteger
required
Basket total in cents. R150.00 = 15000. Must be a positive integer.
storeRefstring
optional
Your store or branch identifier. Required if any campaign uses store targeting.
currencystring
optional
3-letter ISO currency code. Defaults to "ZAR".
productsarray
optional
Line items for product-purchase campaigns. Each item has sku, quantity, unitPrice (cents), and optional categories[].

Response 200

transactionIdstring uuid
required
Internal transaction ID
transactionRefstring
required
Echoes your transactionRef
memberIdstring uuid
required
Internal member UUID
memberCreatedboolean
required
true when this call auto-created the member
pointsAwardedinteger
required
Total points awarded across all matched campaigns
pointsBalanceinteger
required
Member's updated points balance after this transaction
campaignsarray
required
One entry per campaign that fired.
campaignIdstring uuid
required
Campaign UUID
campaignNamestring
required
Campaign display name
pointsEarnedinteger
required
Points awarded by this campaign
rewardIdsstring[]
required
UUIDs of any rewards (vouchers, gift cards) issued
stateenum
required
"PROCESSED" or "FAILED"
_debugobject
optional
Only present on sk_test_* keys when no campaigns matched. Explains why each campaign skipped.
activeCampaignsinteger
required
Count of active campaigns evaluated
campaignChecksarray
required
One entry per campaign that did not fire, with reason code

Debug hints

When campaigns is empty on a test key, _debug.campaignChecks tells you exactly why each campaign skipped. Common reasons: CAMPAIGN_NOT_ACTIVE, SEGMENT_MISMATCH, BELOW_MIN_SPEND, DATE_RANGE.

Error Codes

StatusCodeDescription
400VALIDATION_ERRORMissing or invalid field — check memberRef and amount
401UNAUTHORIZEDMissing or invalid API key
403FORBIDDENAPI key does not belong to this tenant
403MEMBER_SUSPENDEDMember account is suspended
404TENANT_NOT_FOUNDTenant ID does not exist
409TRANSACTION_DUPLICATEtransactionRef already processed — idempotent result returned
429RATE_LIMITED100 req/min limit exceeded — respect Retry-After header
cURL
curl -X POST "https://loyalty-engine-production-e5cb.up.railway.app/v1/tenants/$TENANT_ID/transactions/evaluate" \
  -H "X-API-Key: sk_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "transactionRef": "receipt_001",
    "memberRef":      "customer_27821234567",
    "amount":         15000
  }'

Response

200 OK
{
  "transactionId":  "d2f3a1b4-0e5c-4a8b-9f1d-2c3e4f5a6b7c",
  "transactionRef": "receipt_001",
  "memberId":       "9f4c2e8a-1b2c-3d4e-5f6a-7b8c9d0e1f2a",
  "memberCreated":  true,
  "pointsAwarded":  150,
  "pointsBalance":  150,
  "campaigns": [
    {
      "campaignId":   "5a7b3c9d-...",
      "campaignName": "Spend & Earn",
      "pointsEarned": 150,
      "rewardIds":    []
    }
  ],
  "state": "PROCESSED"
}

Authenticate to test this endpoint live →

Loyalty Engine — Developer Portal