Skip to content
Wallet and passesGeneric passes

Wallet and passes

Generic passes

Issue reusable passes and record visits.

Pilotv1

List generic passs

GET/generic-passes

Scopepasses:read

Requires passes:read. Newest first. Never returns a whole number, issue values, a name or a link. A key limited to programs or branches is 403.

Query

designIduuid
externalCustomerIdstring
serialstring
The whole number (spaces and dashes ignored).
limitinteger
1 to 100. Default 25.
cursorstring
The nextCursor of the previous page.

Returns 200

itemsobject[]Required
items[].idstringRequired
items[].familyenumRequired
One of offer, generic, eventTicket, boardingPass, transit.
items[].designIdstringRequired
items[].designNamestringRequired
items[].maskedSerialstringRequired
•••• 2345.
items[].reusablebooleanRequired
items[].statusenumRequired
One of active, used.
items[].tripTypeenumRequired
Transit passes only: one-way allows one ride, a round trip two. One of oneWay, roundTrip.
items[].usesintegerRequired
items[].usesAllowedinteger or nullRequired
One for an offer, ticket or boarding pass; one or two rides for transit; null for a reusable pass.
items[].validFromstring or nullRequired
The design's window (Dhaka time). Shown by the wallets; not enforced.
items[].validUntilstring or nullRequired
items[].startsAtstring or nullRequired
Event ticket start, boarding pass departure or transit trip time (Dhaka time, YYYY-MM-DDTHH:mm); null when the design has none.
items[].customerIdstring or nullRequired
items[].externalCustomerIdstring or nullRequired
items[].createdAtstringRequired
nextCursorstring or nullRequired
Request
curl "https://app.revisit.cards/v1/developer/generic-passes" \
  -H "Authorization: Bearer $DEVELOPER_API_KEY"
Response
{
  "data": {
    "items": [
      {
        "createdAt": "2026-11-03T08:41:12.000Z",
        "customerId": "eb83b9c0-5619-432d-b857-cef7fcf84edb",
        "designId": "b05ff791-cd85-4fe1-923f-7e3f7e9fdd25",
        "designName": "Mishti Ghor",
        "externalCustomerId": "user-42",
        "family": "offer",
        "id": "d12cc02b-02fe-4a1f-83b0-5414e70fd99c",
        "maskedSerial": "•••• 7310",
        "reusable": false,
        "startsAt": "2026-11-03T08:41:12.000Z",
        "status": "active",
        "tripType": "oneWay",
        "uses": 3,
        "usesAllowed": 20,
        "validFrom": "2026-11-03T08:41:12.000Z",
        "validUntil": "2026-11-03T08:41:12.000Z"
      }
    ],
    "nextCursor": "eyJvZmZzZXQiOjUwfQ"
  },
  "requestId": "c66bd2d6-6ee1-477e-bdce-7916130c5925",
  "success": true
}

Issue a generic pass

POST/generic-passes

Scopepasses:write

Requires passes:write. Issues one pass from a Generic design. sourceEventId is your id for the event: the pass exists once however often the request arrives (replacement keys included); other content under the same id is 409 SOURCE_EVENT_CONFLICT. 422 PASS_TYPE_MISMATCH for a design of another type.

Send an Idempotency-Key header. Safe to retry.

Body

designIduuidRequired
externalCustomerIdstring
holderNamestring
Shown on the pass and at the counter. Never returned.
sourceEventIdstringRequired

Returns 201

idstringRequired
familyenumRequired
One of offer, generic, eventTicket, boardingPass, transit.
designIdstringRequired
designNamestringRequired
maskedSerialstringRequired
•••• 2345.
reusablebooleanRequired
statusenumRequired
One of active, used.
tripTypeenumRequired
Transit passes only: one-way allows one ride, a round trip two. One of oneWay, roundTrip.
usesintegerRequired
usesAllowedinteger or nullRequired
One for an offer, ticket or boarding pass; one or two rides for transit; null for a reusable pass.
validFromstring or nullRequired
The design's window (Dhaka time). Shown by the wallets; not enforced.
validUntilstring or nullRequired
startsAtstring or nullRequired
Event ticket start, boarding pass departure or transit trip time (Dhaka time, YYYY-MM-DDTHH:mm); null when the design has none.
customerIdstring or nullRequired
externalCustomerIdstring or nullRequired
createdAtstringRequired
duplicatebooleanRequired
sourceEventIdstringRequired
warningsobject[]Required
warnings[].codestringRequired
WRONG_DAY or PAST_TIME. Never blocks.
warnings[].messagestringRequired

Errors

  • 409SOURCE_EVENT_CONFLICTthis source event id was already applied with different content (another customer, program, action or amount). Nothing changed.
  • 422PASS_TYPE_MISMATCH
Request
curl -X POST "https://app.revisit.cards/v1/developer/generic-passes" \
  -H "Authorization: Bearer $DEVELOPER_API_KEY" \
  -H "Idempotency-Key: 5f0c2a8e-7b1d-4c3e-9a6f-0d4b8ec77a32" \
  -H "Content-Type: application/json" \
  -d '{
    "designId": "b05ff791-cd85-4fe1-923f-7e3f7e9fdd25",
    "sourceEventId": "order-1001"
  }'
Response
{
  "data": {
    "createdAt": "2026-11-03T08:41:12.000Z",
    "customerId": "eb83b9c0-5619-432d-b857-cef7fcf84edb",
    "designId": "b05ff791-cd85-4fe1-923f-7e3f7e9fdd25",
    "designName": "Mishti Ghor",
    "duplicate": false,
    "externalCustomerId": "user-42",
    "family": "offer",
    "id": "d12cc02b-02fe-4a1f-83b0-5414e70fd99c",
    "maskedSerial": "•••• 7310",
    "reusable": false,
    "sourceEventId": "order-1001",
    "startsAt": "2026-11-03T08:41:12.000Z",
    "status": "active",
    "tripType": "oneWay",
    "uses": 3,
    "usesAllowed": 20,
    "validFrom": "2026-11-03T08:41:12.000Z",
    "validUntil": "2026-11-03T08:41:12.000Z",
    "warnings": [
      {
        "code": "WELCOME10",
        "message": "Your 10th chai is on us this week."
      }
    ]
  },
  "requestId": "ba2362a7-9fa9-42dc-a749-672b3374c630",
  "success": true
}

Read one generic pass with its recent history

GET/generic-passes/{id}

Scopepasses:read

Requires passes:read. uses and status are what count now (a voided use is given back).

Path

iduuidRequired

Returns 200

idstringRequired
familyenumRequired
One of offer, generic, eventTicket, boardingPass, transit.
designIdstringRequired
designNamestringRequired
maskedSerialstringRequired
•••• 2345.
reusablebooleanRequired
statusenumRequired
One of active, used.
tripTypeenumRequired
Transit passes only: one-way allows one ride, a round trip two. One of oneWay, roundTrip.
usesintegerRequired
usesAllowedinteger or nullRequired
One for an offer, ticket or boarding pass; one or two rides for transit; null for a reusable pass.
validFromstring or nullRequired
The design's window (Dhaka time). Shown by the wallets; not enforced.
validUntilstring or nullRequired
startsAtstring or nullRequired
Event ticket start, boarding pass departure or transit trip time (Dhaka time, YYYY-MM-DDTHH:mm); null when the design has none.
customerIdstring or nullRequired
externalCustomerIdstring or nullRequired
createdAtstringRequired
warningsobject[]Required
Event tickets: what a check-in now would warn about.
warnings[].codestringRequired
WRONG_DAY or PAST_TIME. Never blocks.
warnings[].messagestringRequired
historyobject[]Required
history[].idstringRequired
history[].typeenumRequired
One of redeem, visit, checkin, ride, void.
history[].sourceenumRequired
One of api, counter.
history[].voidedbooleanRequired
history[].reversedEventIdstring or nullRequired
history[].createdAtstringRequired
Request
curl "https://app.revisit.cards/v1/developer/generic-passes/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",
    "designId": "b05ff791-cd85-4fe1-923f-7e3f7e9fdd25",
    "designName": "Mishti Ghor",
    "externalCustomerId": "user-42",
    "family": "offer",
    "history": [
      {
        "createdAt": "2026-11-03T08:41:12.000Z",
        "id": "d12cc02b-02fe-4a1f-83b0-5414e70fd99c",
        "reversedEventId": "70d7b7ae-0017-44ae-a9b7-ef2a373b1b5f",
        "source": "api",
        "type": "redeem",
        "voided": false
      }
    ],
    "id": "d12cc02b-02fe-4a1f-83b0-5414e70fd99c",
    "maskedSerial": "•••• 7310",
    "reusable": false,
    "startsAt": "2026-11-03T08:41:12.000Z",
    "status": "active",
    "tripType": "oneWay",
    "uses": 3,
    "usesAllowed": 20,
    "validFrom": "2026-11-03T08:41:12.000Z",
    "validUntil": "2026-11-03T08:41:12.000Z",
    "warnings": [
      {
        "code": "WELCOME10",
        "message": "Your 10th chai is on us this week."
      }
    ]
  },
  "requestId": "09ccce3e-b638-4136-87cf-187fc067cdab",
  "success": true
}

Record a visit on a generic pass

POST/generic-passes/{id}/actions

Scopepasses:write

Requires passes:write. visit once per sourceEventId, through the counter's own rules. A generic pass is reusable: every visit counts, none spends it. 422 UNSUPPORTED_ACTION for any other action or a status/uses/balance field. 400 BRANCH_REQUIRED when several branches are open and branchId is missing.

Send an Idempotency-Key header. Safe to retry.

Path

iduuidRequired

Body

actionenumRequired
redeem on an offer, visit on a generic pass, checkin on an event ticket or boarding pass, ride on a transit pass. One of redeem, visit, checkin, ride.
branchIduuid
sourceEventIdstringRequired

Returns 200

warningsobject[]Required
Check-ins only: heads-ups that did not block the check-in.
warnings[].codestringRequired
WRONG_DAY or PAST_TIME. Never blocks.
warnings[].messagestringRequired
actionenumRequired
One of redeem, visit, checkin, ride.
passIdstringRequired
eventIdstringRequired
usesintegerRequired
statusenumRequired
One of active, used.
duplicatebooleanRequired
sourceEventIdstringRequired

Errors

  • 422UNSUPPORTED_ACTIONthe action is not one a service may take (top-up, spend, set or adjust a balance, void) or the program's card type does not take earning and redeeming from the API yet. Nothing changed.
  • 400BRANCH_REQUIRED
Request
curl -X POST "https://app.revisit.cards/v1/developer/generic-passes/e01b010d-2c65-48e1-83a0-acad79f8d3b4/actions" \
  -H "Authorization: Bearer $DEVELOPER_API_KEY" \
  -H "Idempotency-Key: 5f0c2a8e-7b1d-4c3e-9a6f-0d4b8e90eb06" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "redeem",
    "sourceEventId": "order-1001"
  }'
Response
{
  "data": {
    "action": "redeem",
    "duplicate": false,
    "eventId": "4251c053-b8cd-48e3-885b-da303b8448cc",
    "passId": "309915ad-c546-41d1-b9f6-7446b5e11be7",
    "sourceEventId": "order-1001",
    "status": "active",
    "uses": 3,
    "warnings": [
      {
        "code": "WELCOME10",
        "message": "Your 10th chai is on us this week."
      }
    ]
  },
  "requestId": "7c3a6457-9a77-422d-adc8-20f6b85cd5a7",
  "success": true
}

Give back one visit of a generic pass

POST/generic-passes/{id}/reversals

Scopepasses:write

Requires passes:write (whole-business keys) and an Idempotency-Key. Undoes the visit you sent as sourceEventId, for the refund you identify with reversalId: the use is given back whole and once through the counter's own undo (a void row in the pass history, the pass is active again, one use fewer). There is no partial form: amount, quantity, currency or a state field is 422 UNSUPPORTED_ACTION. A use already undone, at the counter or by an earlier refund, is 409 REVERSAL_EXCEEDS_ORIGINAL. reversalId makes it happen once under any key (duplicate: true); the same id for other content is 409 REVERSAL_CONFLICT. An unknown use, or a pass of another family, is 404. Punchd never refunds the payment.

Send an Idempotency-Key header. Safe to retry.

Path

iduuidRequired

Body

reversalIdstringRequired
Your own id for this refund. It makes the reversal happen once, even under a new Idempotency-Key.
sourceEventIdstringRequired
The sourceEventId of the redeem, visit, check-in or ride being undone.

Returns 200

actionenumRequired
What was undone. One of redeem, visit, checkin, ride.
duplicatebooleanRequired
eventIdstringRequired
The pass history row of the undo.
passIdstringRequired
reversalIdstringRequired
sourceEventIdstringRequired
state"complete"Required
statusenumRequired
One of active, used.
usesintegerRequired
Uses that count after the reversal.

Errors

  • 422UNSUPPORTED_ACTIONthe action is not one a service may take (top-up, spend, set or adjust a balance, void) or the program's card type does not take earning and redeeming from the API yet. Nothing changed.
  • 409REVERSAL_EXCEEDS_ORIGINALa reversal would take back more of the earning than is left (it is already fully reversed, or the refund is larger than what remains). Nothing changed.
  • 409REVERSAL_CONFLICTthis reversalId was already used for a different request (another earning, amount or customer). Nothing changed.
Request
curl -X POST "https://app.revisit.cards/v1/developer/generic-passes/e01b010d-2c65-48e1-83a0-acad79f8d3b4/reversals" \
  -H "Authorization: Bearer $DEVELOPER_API_KEY" \
  -H "Idempotency-Key: 5f0c2a8e-7b1d-4c3e-9a6f-0d4b8e3ca06e" \
  -H "Content-Type: application/json" \
  -d '{
    "reversalId": "refund-1001",
    "sourceEventId": "order-1001"
  }'
Response
{
  "data": {
    "action": "redeem",
    "duplicate": false,
    "eventId": "4251c053-b8cd-48e3-885b-da303b8448cc",
    "passId": "309915ad-c546-41d1-b9f6-7446b5e11be7",
    "reversalId": "refund-1001",
    "sourceEventId": "order-1001",
    "state": "complete",
    "status": "active",
    "uses": 3
  },
  "requestId": "6efd6c16-069d-4e3e-9d4e-ec016246c485",
  "success": true
}

Whether the generic pass was handed to a wallet

GET/generic-passes/{id}/wallet-pass

Scopepasses:read

Requires passes:read. Flags and times, never a link.

Path

iduuidRequired

Returns 200

appleobjectRequired
apple.addedAtstring or nullRequired
apple.availablebooleanRequired
googleobjectRequired
google.addedAtstring or nullRequired
google.availablebooleanRequired
environmentenumRequired
One of live, test.
passIdstringRequired
simulatedbooleanRequired
Request
curl "https://app.revisit.cards/v1/developer/generic-passes/e01b010d-2c65-48e1-83a0-acad79f8d3b4/wallet-pass" \
  -H "Authorization: Bearer $DEVELOPER_API_KEY"
Response
{
  "data": {
    "apple": {
      "addedAt": "2026-11-03T08:41:12.000Z",
      "available": false
    },
    "environment": "live",
    "google": {
      "addedAt": "2026-11-03T08:41:12.000Z",
      "available": false
    },
    "passId": "309915ad-c546-41d1-b9f6-7446b5e11be7",
    "simulated": false
  },
  "requestId": "2cb616a1-e63a-4b04-99ee-50e05873ee75",
  "success": true
}

The generic pass's Apple Wallet file

GET/generic-passes/{id}/wallet-pass/apple

Scopepasses:write

Requires passes:write. The .pkpass raw, no-store, never recorded. Test keys: 403 TEST_MODE_BLOCKED. 409 WALLET_NOT_CONFIGURED.

Path

iduuidRequired

Answers with a file: application/vnd.apple.pkpass.

Errors

  • 403TEST_MODE_BLOCKEDtest mode asked for a real provider (SMS, push, wallet, payment); nothing real is ever sent from a test workspace.
  • 409WALLET_NOT_CONFIGUREDthe wallet asked for (Apple or Google) is not set up on this deployment. Nothing was created.
Request
curl "https://app.revisit.cards/v1/developer/generic-passes/e01b010d-2c65-48e1-83a0-acad79f8d3b4/wallet-pass/apple" \
  -H "Authorization: Bearer $DEVELOPER_API_KEY" \
  -o download
Response
HTTP/1.1 200
Content-Type: application/vnd.apple.pkpass

(file)

The generic pass's Google Wallet save link

GET/generic-passes/{id}/wallet-pass/google

Scopepasses:write

Requires passes:write. A bearer secret: give it to the customer, never log or store it. Not recorded anywhere.

Path

iduuidRequired

Returns 200

provider"google"Required
saveUrlstringRequired
A bearer secret.
Request
curl "https://app.revisit.cards/v1/developer/generic-passes/e01b010d-2c65-48e1-83a0-acad79f8d3b4/wallet-pass/google" \
  -H "Authorization: Bearer $DEVELOPER_API_KEY"
Response
{
  "data": {
    "provider": "google",
    "saveUrl": "https://pay.google.com/gp/v/save/eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJyZXZpc2l0In0"
  },
  "requestId": "0b951ce5-e4ec-4515-a518-053035e24141",
  "success": true
}