Skip to content
LoyaltyCustomers

Loyalty

Customers

Add, link, search, read and update customers.

Pilotv1

You name a customer with your own id, externalCustomerId. Adding or enrolling a customer answers with references only, nothing you sent is echoed back. To reach someone the shop already has, link your id to their member code instead of creating a second customer.

A phone number is never returned. You see maskedPhone (•••• 4821) and the six-character memberCode. You may send a phone to enroll or to look someone up by the whole number. Enrolling never turns on marketing and never undoes an opt-out.

Paths are relative to https://app.revisit.cards/v1/developer.

Search and page the business's customers

GET/customers

Scopecustomers:read

Requires customers:read. Newest customers first, in pages of at most 50 (limit, default 25) with offset up to 10,000; hasMore says whether another page exists. Filters: q (a name fragment, or the six-character member code), phone (the customer's WHOLE number in any form POST /customers accepts; never a partial one: part of a number finds nobody), externalCustomerId (your own id), programId and branchId (customers seen at that branch). Unknown parameters are 422. Whole-number lookups are limited to 20 a minute per key (429). A customer is visible to a key through the programs, and for a branch-limited key the branches, it may use; the memberships listed are only those programs'. A program or branch the key cannot use is 404. Phones come back only as maskedPhone (last four digits); the email is never returned. Erased customers and the owner's test pass are never listed.

Query

qstring
1 to 64 characters.
phonestring
The whole phone number to find.
externalCustomerIdstring
programIduuid
branchIduuid
segmentenum
Only the customers one of the app's buckets names, by the rules the dashboard counts with: ready (a reward can be claimed now), one-away (stamp cards: next stamp fills the card), lapsed (joined over 30 days ago, no visit in 30), new (first membership in the last 30 Dhaka days), champions (5 or more visit days in 30). Read card by card over the cards the key may use; a segment that spans more than 24 card and branch reads or 20,000 customers is 422, narrow it with programId or branchId. One of ready, one-away, lapsed, new, champions.
limitinteger
1 to 50. Default 25.
offsetinteger
0 to 10000. Default 0.

Returns 200

itemsobject[]Required
items[].customerIdstringRequired
items[].externalCustomerIdstring or nullRequired
The id this application linked for the customer; null when it has not named them.
items[].memberCodestringRequired
Six characters staff and the customer see, e.g. K7M4QX.
items[].namestringRequired
items[].maskedPhonestringRequired
Last four digits only, e.g. "•••• 4821"; empty when the customer has no phone.
items[].localestring or nullRequired
items[].createdAtdate-timeRequired
items[].membershipsobject[]Required
Only the memberships in programs this key may use.
items[].memberships[].membershipIdstringRequired
items[].memberships[].programIdstringRequired
items[].memberships[].cardTypestringRequired
items[].memberships[].balanceintegerRequired
items[].memberships[].reservedintegerRequired
Held by active checkout reservations.
items[].memberships[].availableintegerRequired
balance less reserved, never below zero.
items[].memberships[].lifetimeEarnedintegerRequired
items[].memberships[].joinedAtdate-timeRequired
items[].memberships[].joinedBranchIdstring or nullRequired
items[].memberships[].lastActivityAtdate-timeRequired
items[].memberships[].marketingOptInbooleanRequired
False once the customer, the shop or your service withdrew marketing consent. A membership you create starts false.
items[].memberships[].consentobject or nullRequired
What was recorded when the customer joined; null when none was.
limitintegerRequired
offsetintegerRequired
hasMorebooleanRequired
Request
curl "https://app.revisit.cards/v1/developer/customers" \
  -H "Authorization: Bearer $DEVELOPER_API_KEY"
Response
{
  "data": {
    "hasMore": false,
    "items": [
      {
        "createdAt": "2026-11-03T08:41:12.000Z",
        "customerId": "eb83b9c0-5619-432d-b857-cef7fcf84edb",
        "externalCustomerId": "user-42",
        "locale": "en-BD",
        "maskedPhone": "•••• 4821",
        "memberCode": "K7M2QX",
        "memberships": [
          {
            "available": 7,
            "balance": 7,
            "cardType": "stamp",
            "consent": {},
            "joinedAt": "2026-11-03T08:41:12.000Z",
            "joinedBranchId": "1915466d-1961-49fe-b213-b5b7f0692d63",
            "lastActivityAt": "2026-11-03T08:41:12.000Z",
            "lifetimeEarned": 42,
            "marketingOptIn": false,
            "membershipId": "b53ca741-1e76-4ddb-b6a5-998b65c4aff3",
            "programId": "d7595bbd-4342-41b4-9037-2e61a9f8403f",
            "reserved": 0
          }
        ],
        "name": "Nusrat Jahan"
      }
    ],
    "limit": 50,
    "offset": 0
  },
  "requestId": "ecca2c65-ccbf-47cd-ba79-cdad1e6442c7",
  "success": true
}

Add or update a customer by your own customer id

POST/customers

Scopecustomers:write

Requires customers:write and an Idempotency-Key. Names the customer with your id; every detail is optional. The first call creates the customer, later calls change only the details they carry. Never records or changes marketing consent, never merges customers: a phone that already belongs to another customer, or an id that already points elsewhere, is 409 CUSTOMER_REFERENCE_CONFLICT. The answer holds references only, never what you sent. A key limited to some branches or programs must enroll instead.

Send an Idempotency-Key header. Safe to retry.

Body

externalCustomerIdstringRequired
Your own id for the customer. Unique per business and application, and separate in test and live.
namestring
1 to 60 characters.
phonestring
A Bangladesh mobile in any form (01XXXXXXXXX or +8801XXXXXXXXX) or another country as +<country><number> (+447700900123). Stored sealed; never returned.
emailemail
Stored sealed; never returned.
localestring
Language tag such as en, bn or en-BD.

Returns 200

createdbooleanRequired
customerIdstringRequired
externalCustomerIdstringRequired

Errors

  • 409CUSTOMER_REFERENCE_CONFLICTthe customer id or the phone points at a different customer than the one this request would create or change. Nothing is merged or moved.
Request
curl -X POST "https://app.revisit.cards/v1/developer/customers" \
  -H "Authorization: Bearer $DEVELOPER_API_KEY" \
  -H "Idempotency-Key: 5f0c2a8e-7b1d-4c3e-9a6f-0d4b8ed2dddb" \
  -H "Content-Type: application/json" \
  -d '{
    "externalCustomerId": "user-42"
  }'
Response
{
  "data": {
    "created": false,
    "customerId": "eb83b9c0-5619-432d-b857-cef7fcf84edb",
    "externalCustomerId": "user-42"
  },
  "requestId": "39847d18-6b60-4fb7-bb4f-44b98e9282fb",
  "success": true
}

Count customers

GET/customers/count

Scopecustomers:read

Requires customers:read. The customers a list with the same programId and branchId would hold, under the same visibility rules.

Query

programIduuid
branchIduuid
segmentenum
Only the customers one of the app's buckets names, by the rules the dashboard counts with: ready (a reward can be claimed now), one-away (stamp cards: next stamp fills the card), lapsed (joined over 30 days ago, no visit in 30), new (first membership in the last 30 Dhaka days), champions (5 or more visit days in 30). Read card by card over the cards the key may use; a segment that spans more than 24 card and branch reads or 20,000 customers is 422, narrow it with programId or branchId. One of ready, one-away, lapsed, new, champions.

Returns 200

countintegerRequired
Request
curl "https://app.revisit.cards/v1/developer/customers/count" \
  -H "Authorization: Bearer $DEVELOPER_API_KEY"
Response
{
  "data": {
    "count": 12
  },
  "requestId": "27d25b2c-341a-42e4-92a9-492898fc34c2",
  "success": true
}

Read a customer's card history

GET/customers/{id}/history

Scopecustomers:read

Requires customers:read. The customer's ledger rows (stamps, points, redemptions, top-ups, spends, bonuses, resets and reversals) on the cards, and for a branch-limited key the branches, the key may use, newest first, in pages of at most 50 (limit, default 25) walked with the opaque next value passed back as cursor. Optional programId and branchId narrow it. Rows with no branch on record are hidden from a branch-limited key. Ledger facts only: delta is the balance change, voided says a later reversal undid the row, and there is no staff name, free text, name or phone. The owner's test rows never appear. Unknown, erased, other-business and out-of-limits customers answer 404; a cursor this API did not return is 422.

Path

iduuidRequired

Query

programIduuid
branchIduuid
limitinteger
1 to 50. Default 25.
cursorstring

Returns 200

nextstring or nullRequired
Pass back as cursor for the next page; null on the last.
itemsobject[]Required
items[].idstringRequired
items[].membershipIdstringRequired
items[].programIdstringRequired
items[].branchIdstring or nullRequired
items[].typeenumRequired
One of STAMP, REDEEM, RESET, TOPUP, SPEND, BONUS, VOID.
items[].deltaintegerRequired
Change to the balance (negative for a redemption or spend).
items[].amountinteger or nullRequired
items[].rewardNamestring or nullRequired
items[].voidedbooleanRequired
items[].voidsTransactionIdstring or nullRequired
items[].createdAtdate-timeRequired
Request
curl "https://app.revisit.cards/v1/developer/customers/e01b010d-2c65-48e1-83a0-acad79f8d3b4/history" \
  -H "Authorization: Bearer $DEVELOPER_API_KEY"
Response
{
  "data": {
    "items": [
      {
        "amount": 1250,
        "branchId": "5eff65d7-d01c-4bd3-b26a-3d06b21fd005",
        "createdAt": "2026-11-03T08:41:12.000Z",
        "delta": 1,
        "id": "d12cc02b-02fe-4a1f-83b0-5414e70fd99c",
        "membershipId": "b53ca741-1e76-4ddb-b6a5-998b65c4aff3",
        "programId": "d7595bbd-4342-41b4-9037-2e61a9f8403f",
        "rewardName": "Free chai",
        "type": "STAMP",
        "voided": false,
        "voidsTransactionId": "a7435d7c-7442-4213-a2d2-a75495daf9bf"
      }
    ],
    "next": "eyJvZmZzZXQiOjUwfQ"
  },
  "requestId": "32972ce8-c708-4fbc-8458-ce030210351f",
  "success": true
}

Read one customer

GET/customers/{id}

Scopecustomers:read

Requires customers:read. Unknown, erased, other-business and out-of-limits customers all answer 404.

Path

iduuidRequired

Returns 200

customerIdstringRequired
externalCustomerIdstring or nullRequired
The id this application linked for the customer; null when it has not named them.
memberCodestringRequired
Six characters staff and the customer see, e.g. K7M4QX.
namestringRequired
maskedPhonestringRequired
Last four digits only, e.g. "•••• 4821"; empty when the customer has no phone.
localestring or nullRequired
createdAtdate-timeRequired
membershipsobject[]Required
Only the memberships in programs this key may use.
memberships[].membershipIdstringRequired
memberships[].programIdstringRequired
memberships[].cardTypestringRequired
memberships[].balanceintegerRequired
memberships[].reservedintegerRequired
Held by active checkout reservations.
memberships[].availableintegerRequired
balance less reserved, never below zero.
memberships[].lifetimeEarnedintegerRequired
memberships[].joinedAtdate-timeRequired
memberships[].joinedBranchIdstring or nullRequired
memberships[].lastActivityAtdate-timeRequired
memberships[].marketingOptInbooleanRequired
False once the customer, the shop or your service withdrew marketing consent. A membership you create starts false.
memberships[].consentobject or nullRequired
What was recorded when the customer joined; null when none was.
memberships[].consent.atdate-timeRequired
memberships[].consent.sourceenumRequired
self - the customer; merchant - the shop's attestation. One of self, merchant.
memberships[].consent.versionstring or nullRequired
Request
curl "https://app.revisit.cards/v1/developer/customers/e01b010d-2c65-48e1-83a0-acad79f8d3b4" \
  -H "Authorization: Bearer $DEVELOPER_API_KEY"
Response
{
  "data": {
    "createdAt": "2026-11-03T08:41:12.000Z",
    "customerId": "eb83b9c0-5619-432d-b857-cef7fcf84edb",
    "externalCustomerId": "user-42",
    "locale": "en-BD",
    "maskedPhone": "•••• 4821",
    "memberCode": "K7M2QX",
    "memberships": [
      {
        "available": 7,
        "balance": 7,
        "cardType": "stamp",
        "consent": {
          "at": "2026-11-03T08:41:12.000Z",
          "source": "self",
          "version": "2026-11-02"
        },
        "joinedAt": "2026-11-03T08:41:12.000Z",
        "joinedBranchId": "1915466d-1961-49fe-b213-b5b7f0692d63",
        "lastActivityAt": "2026-11-03T08:41:12.000Z",
        "lifetimeEarned": 42,
        "marketingOptIn": false,
        "membershipId": "b53ca741-1e76-4ddb-b6a5-998b65c4aff3",
        "programId": "d7595bbd-4342-41b4-9037-2e61a9f8403f",
        "reserved": 0
      }
    ],
    "name": "Nusrat Jahan"
  },
  "requestId": "00609c78-cb53-4728-aa53-0d2d0bf14cad",
  "success": true
}

Change a customer's details

PATCH/customers/{id}

Scopecustomers:write

Requires customers:write and an Idempotency-Key. Name the customer by Revisit's id. Only the fields sent change; the answer lists which kinds changed (name, phone, email, locale), never the values. A phone that belongs to another customer is 409 CUSTOMER_REFERENCE_CONFLICT (customers are never merged). Unknown fields (free-form profile data, consent) and an empty body are 422. Consent and opt-outs are never touched. A key limited to some branches or programs cannot change customers (403).

Send an Idempotency-Key header. Safe to retry.

Path

iduuidRequired

Body

namestring
1 to 60 characters.
phonestring
A Bangladesh mobile in any form or another country as +<country><number>. Stored sealed; never returned.
emailemail
Stored sealed; never returned.
localestring
Language tag such as en, bn or en-BD.

Returns 200

customerIdstringRequired
changedenum[]Required
Which details this request changed; empty when nothing differed.

Errors

  • 409CUSTOMER_REFERENCE_CONFLICTthe customer id or the phone points at a different customer than the one this request would create or change. Nothing is merged or moved.
Request
curl -X PATCH "https://app.revisit.cards/v1/developer/customers/e01b010d-2c65-48e1-83a0-acad79f8d3b4" \
  -H "Authorization: Bearer $DEVELOPER_API_KEY" \
  -H "Idempotency-Key: 5f0c2a8e-7b1d-4c3e-9a6f-0d4b8ebe819a" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Nusrat Jahan",
    "phone": "01XXXXXXXXX"
  }'
Response
{
  "data": {
    "changed": [
      "name"
    ],
    "customerId": "eb83b9c0-5619-432d-b857-cef7fcf84edb"
  },
  "requestId": "26277370-ac46-49d7-b2ba-ad86bca840b8",
  "success": true
}

Permanently erase a customer

DELETE/customers/{id}

Scopecustomers:erase

Requires customers:erase and an Idempotency-Key. This cannot be undone. It is the same erasure the shop's own staff run in the app: the customer's name, phone, email, member code, opt-out link, your ids for them (so the same id adds a new customer later), queued notifications, wallet device registrations and holder names on issued passes are removed or cleared, any details still waiting in an unfinished import row are withdrawn (the row fails CUSTOMER_ERASED), and every export file that held them is wiped. What stays is anonymous: the cards' balances and the transaction ledger, issued passes (unlinked), and the audit trail (which records the key, never a detail). Offers are not sent to an erased customer. The scope is never part of the Read-only or Full access presets. A key limited to some branches or programs cannot erase (403), since a customer belongs to the whole business. A repeat with the same key replays; a new key on an already erased customer answers 200 with alreadyErased: true. Another business's or environment's customer, the owner's test pass and an unknown id are 404.

Send an Idempotency-Key header. Safe to retry.

Path

iduuidRequired

Returns 200

customerIdstringRequired
erasedtrueRequired
alreadyErasedbooleanRequired
True when this customer was erased before this request.
Request
curl -X DELETE "https://app.revisit.cards/v1/developer/customers/e01b010d-2c65-48e1-83a0-acad79f8d3b4" \
  -H "Authorization: Bearer $DEVELOPER_API_KEY" \
  -H "Idempotency-Key: 5f0c2a8e-7b1d-4c3e-9a6f-0d4b8e10935a"
Response
{
  "data": {
    "alreadyErased": false,
    "customerId": "eb83b9c0-5619-432d-b857-cef7fcf84edb",
    "erased": true
  },
  "requestId": "fb2b8a51-8315-49ca-8d56-35e53f19c789",
  "success": true
}