| Time | Status | User Agent | |
|---|---|---|---|
Retrieving recent requests… | |||
This is the v2 API for redeeming points. If you are on the older API, see Redeem Points (v1.1) for POST /v1.1/points/redeem.
Redeem points for a customer. By default, points are deducted from the customer's individual wallet. If the customer is an active member of a UserGroup2 group and the org has ENABLE_CROSS_MEMBER_REDEMPTION enabled, points are instead drawn from the combined group balance in FEFO (First Expiry, First Out) order — the earliest-expiring batch across all group members is consumed first.
What this API supports
- Redeem points from an individual customer's wallet.
- Redeem from the combined balance of all active group members in a single transaction. This requires the
ENABLE_CROSS_MEMBER_REDEMPTIONorg-level configuration to be enabled. To enable this, raise a JIRA ticket to the Capillary support team. - FEFO (First Expiry, First Out) ordering across all group members — the earliest-expiring batch is drawn first. When two batches share the same expiry date, the batch with the earlier award date takes priority; if both match, the lower customer ID breaks the tie.
- Per-source-member breakdown in the response (
crossMemberRedemptionBreakup[]) showing exactly whose points were drawn and from which expiry batch. - Backward compatible: callers not enrolled in a UserGroup2 group, or orgs without
ENABLE_CROSS_MEMBER_REDEMPTIONenabled, take the standard individual redemption path unchanged. ThegroupRedemptionfield does not control routing — cross-member activation is determined by org configuration and group membership.
Example request
curl -X POST 'https://{host}/v2/customers/1003/redemptions' \
-u USERNAME:{password} \
-H 'Content-Type: application/json' \
-d '{
"redemptionType": "POINTS",
"points": 350,
"transactionNumber": "TXN-882291",
"validationCode": "VC-1234",
"source": "INSTORE",
"commit": true,
"externalReferenceNumber": "TXN-882291"
}'API Quick Reference
POST /v2/customers/{id}/redemptions
Request
└─ root (object)
├─ redemptionType (string)
├─ points (number)
├─ transactionNumber (string)
├─ validationCode (string)
├─ source (string)
├─ commit (boolean)
├─ skipValidation (boolean)
├─ groupRedemption (boolean)
├─ externalReferenceNumber (string)
└─ notes (string)
Response
└─ entity (object)
├─ redemptionId (string)
├─ userId (number)
├─ points (number)
├─ remainingPoints (number)
├─ redeemed (boolean)
├─ isGroupRedemption (boolean)
└─ crossMemberRedemptionBreakup [] (present only on group redemptions)
├─ memberId (number)
├─ pointsRedeemed (number)
└─ expiryDate (string — ISO-8601)
Prerequisites
- Basic authentication. Credentials must be authorised for the org that owns the customer.
- For group redemptions, the org must have
ENABLE_CROSS_MEMBER_REDEMPTIONenabled. To enable this, raise a JIRA ticket to the Capillary support team. - For group redemptions, the transacting customer (
{id}) must be an active member of a UserGroup2 group with theallow_points_redemptionpermission. Use the Update permissions API to grant this permission.
Path parameters
| Field | Type | Required | Description |
|---|---|---|---|
id | Long | Yes | Customer ID of the member initiating the redemption. |
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
redemptionType | String | Yes | Type of redemption. Supported values: POINTS. |
points | Number | Yes | Number of points to redeem. For group redemptions, points are drawn from the combined group balance in FEFO order. |
transactionNumber | String | Yes | Unique identifier for the transaction. |
validationCode | String | Conditional | Authorization code issued to the customer to confirm the redemption. The code is verified against a valid code on record for this org. Required when validation enforcement is enabled at the org level. |
source | String | Yes | Source of the redemption request. Supported values: INSTORE. |
commit | Boolean | Yes | Set to true to finalize and commit the redemption. When false, the call performs a validation dry run without deducting points. |
skipValidation | Boolean | Optional | When true, bypasses the validation code check. Only effective when the org has the validation override config enabled. Defaults to false. |
groupRedemption | Boolean | Optional | Set to true to redeem group points. |
externalReferenceNumber | String | Optional | A plain string reference identifier for the points redemption attempt. Each externalReferenceNumber must be unique for a redemption. This is used for an idempotency check. There is no character limit for this parameter. |
notes | String | Optional | Notes or additional information about the redemption. |
Example response
{
"status": {
"success": true,
"code": 201,
"message": "SUCCESS"
},
"entity": {
"redemptionId": "RDM-5002",
"userId": 1003,
"points": 100,
"remainingPoints": 400,
"redeemed": true,
"isGroupRedemption": false
}
}{
"status": {
"success": true,
"code": 201,
"message": "SUCCESS"
},
"entity": {
"redemptionId": "RDM-5001",
"userId": 1003,
"points": 350,
"remainingPoints": 160,
"redeemed": true,
"isGroupRedemption": true,
"crossMemberRedemptionBreakup": [
{ "memberId": 1004, "pointsRedeemed": 10, "expiryDate": "2026-04-02T00:00:00Z" },
{ "memberId": 1001, "pointsRedeemed": 100, "expiryDate": "2026-04-05T00:00:00Z" },
{ "memberId": 1002, "pointsRedeemed": 240, "expiryDate": "2026-04-10T00:00:00Z" }
]
}
}Response parameters
| Field | Type | Description |
|---|---|---|
redemptionId | String | Unique identifier for this redemption transaction. |
userId | Long | Customer ID of the transacting member. |
points | Number | Total points redeemed in this transaction. |
remainingPoints | Number | Remaining redeemable balance for the transacting member after the redemption. |
redeemed | Boolean | true when the redemption succeeded. |
isGroupRedemption | Boolean | true when group redemption was applied. |
crossMemberRedemptionBreakup | Array | Per-source-member breakdown. Present only when isGroupRedemption is true. null for individual redemptions. |
.memberId | Long | Customer ID of the group member whose points were drawn. |
.pointsRedeemed | Number | Points drawn from this member's wallet. Entries are ordered by FEFO (earliest expiry first). |
.expiryDate | String (ISO-8601) | Expiry timestamp of the points batch consumed from this member's wallet. |
How group redemption works
When a group member redeems points, the API draws from the earliest-expiring batches across all active group members first — this is called FEFO (First Expiry, First Out) ordering. Points expiring soonest are consumed before those with later expiry dates.
Example
A group of four members has a combined balance of 1,410 points. Two members each hold a 100-point batch expiring in 2 days — earlier than any other batch in the group. The caller requests 200 points.
The API draws 100 points from each of the two earliest-expiring batches, leaving all other members' points untouched.
"crossMemberRedemptionBreakup": [
{ "memberId": 1002, "pointsRedeemed": 100, "expiryDate": "2026-05-20T00:00:00Z" },
{ "memberId": 1003, "pointsRedeemed": 100, "expiryDate": "2026-05-20T00:00:00Z" }
]Individual redemption
If the customer is not part of a group, or if group redemption is not enabled for the org, points are deducted only from that customer's own wallet.
Error codes
| Code | Type | Description |
|---|---|---|
| 802 | Error | Invalid customer ID — the {id} in the path does not correspond to an active customer. |
| 813 | Error | Insufficient balance — the available redeemable balance (individual wallet, or the group's combined balance for group redemptions) is less than the requested points value. |
| 744 | Error | Duplicate externalReferenceNumber — a prior redemption with this value already exists on this org. |
| 400 | Error | Required field missing or invalid value (e.g., source absent). |
| 700 | Error | Invalid redemption type. Returned when redemptionType is set to an unrecognized value (for example, lowercase "points" instead of "POINTS"). The HTTP status is 201 and success is true, but entity.redemptionStatus.success is false. |
| 403 | Error | One or more group members carry an active fraud flag (CONFIRMED, RECONFIRMED, or INTERNAL). The entire redemption is blocked. |
| 404 | Error | For group redemptions: the transacting member is not an active member of a cross-member-eligible group, or the group does not exist for this org. |
| 500 | Error | Internal server error. Retry the request after a short delay. |
401Unauthorized — invalid or missing credentials
500Internal server error
