Skip to content

Earn 30% on every license you refer. Join the affiliate program

Partner endpoints.

Complete endpoint reference for partner-scoped agent operations.

Sep 30, 2026

All partner endpoints are prefixed with /api/agent/v1/partner and require a partner-scoped key (rl_agent_).

Common patterns

All partner endpoints share these behaviors:

  • Multi-tenant isolation. A partner key can access resources created by that partner and no other
  • Canonical API contracts. The platform validates requests against the live agent schema, permission gates, and ownership checks
  • JSON request/response. Send and receive application/json
  • Pagination. List endpoints support ?page=1&per_page=25 query parameters

Health check

GET /api/agent/v1/health

Available to all key roles. Returns key identity, scopes, and owner information. Use this to verify your key works before making other requests.

No scope required.


Clubs

Clubs organize a partner's staff and operations. Most resources (cards, staff) belong to a club.

List clubs

GET /api/agent/v1/partner/clubs

Scope: read or write:clubs

Get club

GET /api/agent/v1/partner/clubs/{id}

Scope: read or write:clubs

Create club

POST /api/agent/v1/partner/clubs

Scope: write:clubs

{
  "name": "Downtown Location",
  "is_active": true
}

Update club

PUT /api/agent/v1/partner/clubs/{id}

Scope: write:clubs

Delete club

DELETE /api/agent/v1/partner/clubs/{id}

Scope: write:clubs


Loyalty cards

Loyalty cards define point-earning rules and associated rewards.

List cards

GET /api/agent/v1/partner/cards

Scope: read or write:cards

Get card

GET /api/agent/v1/partner/cards/{id}

Scope: read or write:cards

Create card

POST /api/agent/v1/partner/cards

Scope: write:cards

Update card

PUT /api/agent/v1/partner/cards/{id}

Scope: write:cards

Delete card

DELETE /api/agent/v1/partner/cards/{id}

Scope: write:cards


Rewards

Rewards are what members save up for. Rewards can be linked to one or more loyalty cards.

List rewards

GET /api/agent/v1/partner/rewards

Scope: read or write:rewards

Get reward

GET /api/agent/v1/partner/rewards/{id}

Scope: read or write:rewards

Create reward

POST /api/agent/v1/partner/rewards

Scope: write:rewards

Update reward

PUT /api/agent/v1/partner/rewards/{id}

Scope: write:rewards

Delete reward

DELETE /api/agent/v1/partner/rewards/{id}

Scope: write:rewards


Transactions

Transactions handle the core earn-and-burn flow. POS integrations spend most of their calls here.

List transactions

GET /api/agent/v1/partner/transactions

Scope: read or write:transactions

Lists transactions for your partner account, newest first. Supports the following query parameters:

Parameter Type Description
member_identifier string Filter by member (UUID, email, or unique_identifier)
card_id UUID Filter by a specific loyalty card
event string Filter by event type (e.g., staff_credited_points_for_purchase)
from date Start date (Y-m-d)
to date End date (Y-m-d)
per_page int Results per page (default 25, max 100)

Record a purchase (award points)

POST /api/agent/v1/partner/transactions/purchase

Scope: write:transactions

{
  "card_id": "uuid-of-loyalty-card",
  "member_identifier": "[email protected]",
  "purchase_amount": 24.50,
  "staff_id": "uuid-of-staff-member",
  "note": "Coffee and pastry"
}

Member identification. The member_identifier field accepts multiple formats:

  • Member UUID
  • Email address
  • Member number
  • Unique identifier

You can pass any of these formats and the API will resolve the member. This flexibility matters for POS systems that may have nothing but a customer email or loyalty number.

You can also pass a points field (integer) to override the automatic point calculation. This is useful for custom promotions or manual adjustments. The card's max_points_per_purchase still caps the override after tier multipliers, so you can never exceed the configured maximum.

On a retry-safe purchase, points also has an absolute ceiling of 2147483647, the largest value a single award can be recorded as. A larger override is refused with 422, and so is a sale whose calculated award would land past it once tier and bonus-window multipliers are applied: the check runs before the sale is recorded, so it is a request to correct, never a retry to repeat. A card whose welcome bonus is configured beyond that ceiling is refused the same way, since the bonus is a second award the first sale would have to record.

The staff_id is optional. It attributes the transaction to a specific staff member for reporting. Without it, the platform attributes the transaction to "System". A staff member you name must belong to your partner account and have access to the card's club. Naming one who does not is refused either way, but the answer differs: a retry-safe purchase returns 404 before anything is recorded, while a purchase without source_reference returns 422 TRANSACTION_FAILED.

Retry-safe purchases

Add source_reference and the sale is recorded once, however many times the request arrives:

{
  "card_id": "uuid-of-loyalty-card",
  "member_identifier": "[email protected]",
  "purchase_amount": "24.50",
  "currency": "EUR",
  "source_completed_at": "2026-08-26T09:41:07+02:00",
  "source_reference": "pos:store-1:till-3:98441",
  "note": "Coffee and pastry"
}
Field Rules
source_reference Optional. Turns on retry-safe recording. Up to 128 characters, case-sensitive, starting with a letter or digit, then letters, digits, ., _, :, or -. Include platform, store, till, and sale id. Never an email address, phone number, customer name, or credential.
currency Required with source_reference. Three uppercase letters, and it must match the card's currency exactly. Amounts are never converted.
source_completed_at Required with source_reference. An ISO 8601 instant with whole seconds, written either with a numeric offset (2026-08-26T09:41:07+02:00) or with the UTC Z designator (2026-08-26T07:41:07Z). The two are equivalent, including on a retry, so a queue may re-serialize one as the other. Fractional seconds (2026-08-26T07:41:07.000Z) are rejected; trim them if your till emits them. So is any offset beyond ±14:00, which no real time zone uses. For a new sale the time may be at most 7 days old and 5 minutes in the future. It also sets the transaction time, so a delayed sale earns by the bonus window that was in force when it happened, and its points expire from that moment.
purchase_amount Send it as a string with a retry-safe purchase ("24.50") so the exact amount survives, and omit it only when you send points instead.

Identity is your business plus the reference, so two businesses may use the same reference and two tills inside one business must not. Replacing, revoking, or deleting an Integration API key does not reset a recorded sale.

What is kept after a correction or an erasure. When a recorded sale is corrected away, or a member removes their relationship with your business or erases their account, the sale's own facts go with it: the points, the balance, the amount, the currency, the link to the transaction, and the protected copy of the request. What remains is your business, a one-way digest of the sale reference, and the fact that the reference was settled.

That digest is kept for the lifetime of the business, for one reason: a till that retries an erased sale has to be told the sale is settled (410), or erasure would become a way to make one purchase pay out twice. It is not used for anything else. No profiling, no marketing, no analytics. It is pseudonymous rather than anonymous: it is derived from a reference you chose, so anyone holding that reference can recompute it. Deleting the business removes it along with everything else.

Presentation is ignored when the app compares a retry with the original: 24.5 and 24.50, +00:00 and Z for the same instant, a different time zone for the same instant, a different key order, and a different note all still count as the same sale. The sale's own facts are not: member_identifier, staff_id, and points are all part of what identifies the sale, so a retry must repeat them exactly. Sending a different member_identifier returns 409 even when it resolves to the same member, and so does a retry that drops the staff_id the first call carried. Worth checking if a queue replays your requests without the cashier context.

Responses:

Situation HTTP Body
Recorded 201 The purchase facts, plus currency, source_completed_at, source_reference, replayed: false, transaction_status: active
Identical request, already recorded 200 The original frozen facts, replayed: true, and the current transaction_status (active or voided)
Same reference, different sale facts 409 PURCHASE_REFERENCE_CONFLICT, retry_strategy: no_retry
Same reference, still being processed 409 PURCHASE_REFERENCE_IN_FLIGHT, retry_strategy: backoff, Retry-After: 2
Temporary failure while recording 503 PURCHASE_RETRYABLE_FAILURE, retry_strategy: backoff. Retry the identical request.
Sale record's app key is missing 503 PURCHASE_CLAIM_KEY_UNAVAILABLE, retry_strategy: contact_support. Nothing is awarded or changed; the operator restores the key from backup.
Original purchase corrected or erased 410 PURCHASE_REFERENCE_CONSUMED, retry_strategy: no_retry. The sale stays settled and no member facts are returned.
Currency differs from the card 422 PURCHASE_CURRENCY_MISMATCH, and no sale is recorded
Source time outside the window 422 SOURCE_COMPLETED_AT_OUT_OF_RANGE, and no sale is recorded. An identical retry of an already recorded sale is unaffected.

A replay answers from the stored record, so it survives edits to the card, a deactivated member, a deleted staff member, and a replaced Integration API key. Without source_reference the endpoint keeps its original behavior: every call awards points again.

Redeem a reward (deduct points)

POST /api/agent/v1/partner/transactions/redeem

Scope: write:rewards

{
  "card_id": "uuid-of-loyalty-card",
  "reward_id": "uuid-of-reward",
  "member_identifier": "[email protected]",
  "staff_id": "uuid-of-staff-member"
}

The staff_id is optional. Without it, the platform attributes the redemption to "System". This enables headless integrations (Shopify, WooCommerce) that do not have staff accounts.

Successful redemption responses include transaction_id, points_deducted, member_balance, new_balance, reward_id, reward, card_id, and member_id.

Deduct points (custom deduction)

POST /api/agent/v1/partner/transactions/deduct

Scope: write:transactions

{
  "card_id": "uuid-of-loyalty-card",
  "member_identifier": "[email protected]",
  "points": 500,
  "note": "Gift card redemption - $50 Amazon card",
  "reference": "giftcard:order:12345",
  "staff_id": "uuid-of-staff-member"
}

Deducts a custom number of points from a member's card balance. The deduction consumes points in FIFO order (oldest first). Deductions require a note for the audit trail.

Use this for off-platform rewards like gift cards or external services, without needing a reward object.

The reference field is optional. It links the deduction to an external system for reconciliation.

The staff_id is optional. If you omit it, the platform records the transaction as "Partner".

A deduction fails with INSUFFICIENT_POINTS if the member does not have enough points. The tier system ignores deductions.

Successful deduction responses include transaction_id, points_deducted, member_balance, new_balance, card_id, and member_id.


Members

Member endpoints are read for partner keys, no writes. The agent API cannot create or modify members. They self-register through the platform.

List and detail return only members who have interacted with your business: earned points, collected a stamp, redeemed a voucher, or used a pass. A member who joined a card but has no interaction yet answers not-found, indistinguishable from an unknown id. The transaction endpoints accept that member's identifier regardless. See First-time customers.

List members

GET /api/agent/v1/partner/members

Scope: read

Get member

GET /api/agent/v1/partner/members/{id}

Scope: read

Get member balance

GET /api/agent/v1/partner/members/{id}/balance/{cardId}

Scope: read

Returns the member's point balance for a specific loyalty card.

Member list/detail responses expose the hardened public payload, nothing more: id, unique_identifier, name, email, locale, currency, time_zone, last_login_at, created_at, updated_at, avatar, is_anonymous.


Achievements

A read-only view of the partner's achievements program. Program settings change in the partner dashboard, not through the API. Both endpoints require the achievements feature (achievements_permission, from the plan or the per-partner override); without it they answer 403.

Get the program

GET /api/agent/v1/partner/achievements

Scope: read

Returns the program (status of active, paused, or inactive, whether a history import is running, activated_at, week_starts_on, and the catalog version), the configured rules (per achievement: key, name, group, threshold, enabled, and the reward's public envelope of type, cap, and window, never the linked product), and aggregate insights while the program is active: members with an achievement, awards in the last 30 days, weekly-run and near-milestone counts, and reward usage. Insights are aggregates only, never member listings.

Get a member's achievements

GET /api/agent/v1/partner/members/{id}/achievements

Scope: read

Returns one member's progress at this business (loyalty days, current and best weekly run, the last qualifying week, distinct loyalty options used, first and last activity) and their paginated earned achievements, each with key, name, group, origin (live, or backfill for an achievement recognized by the history import), earned date, and a safe reward state (none, pending, delivered, or failed). Only members with a relationship at this business resolve; anyone else answers not-found. Voided achievements never appear.


Stamp cards

Stamp cards work like digital punch cards. Members collect stamps and earn a reward when the card is complete.

List stamp cards

GET /api/agent/v1/partner/stamp-cards

Scope: read or write:stamps

Get stamp card

GET /api/agent/v1/partner/stamp-cards/{id}

Scope: read or write:stamps

Create stamp card

POST /api/agent/v1/partner/stamp-cards

Scope: write:stamps

Update stamp card

PUT /api/agent/v1/partner/stamp-cards/{id}

Scope: write:stamps

Delete stamp card

DELETE /api/agent/v1/partner/stamp-cards/{id}

Scope: write:stamps

Add stamps

POST /api/agent/v1/partner/stamp-cards/{id}/stamps

Scope: write:stamps

Award stamps to a member on a specific stamp card.

A single call adds up to one full card (stamps_required) when the card has no per-transaction cap, or up to the configured cap otherwise. The absolute ceiling is 100.

Redeem stamp reward

POST /api/agent/v1/partner/stamp-cards/{id}/redeem

Scope: write:stamps

Redeem the stamp card reward when a member has collected all required stamps.

Use canonical create/update fields: stamps_expire_days and requires_physical_claim.


Vouchers

Vouchers provide instant-value discounts through promotional codes.

List vouchers

GET /api/agent/v1/partner/vouchers

Scope: read or write:vouchers

Get voucher

GET /api/agent/v1/partner/vouchers/{id}

Scope: read or write:vouchers

Create voucher

POST /api/agent/v1/partner/vouchers

Scope: write:vouchers

Update voucher

PUT /api/agent/v1/partner/vouchers/{id}

Scope: write:vouchers

Delete voucher

DELETE /api/agent/v1/partner/vouchers/{id}

Scope: write:vouchers

Validate voucher code

POST /api/agent/v1/partner/vouchers/validate

Scope: write:vouchers

Check if a voucher code is valid and redeemable without redeeming it.

Use canonical voucher fields: type, value, valid_from, valid_until, max_uses_total, and max_uses_per_member. code is optional on create. The platform generates one when you omit it.

Validate request body:

  • code
  • member_identifier
  • club_id
  • order_amount (optional, minor units)

Validate response fields:

  • valid
  • voucher_id
  • code
  • name
  • type
  • value
  • currency
  • discount_amount
  • capped
  • original_amount
  • final_amount
  • times_used
  • remaining_uses
  • valid_until

Redeem voucher

POST /api/agent/v1/partner/vouchers/{id}/redeem

Scope: write:vouchers

Redeem request body:

  • member_identifier
  • order_amount (optional, minor units)
  • order_reference (optional)

Redeem response fields:

  • voucher_id
  • code
  • type
  • member_id
  • discount_amount
  • points_awarded
  • remaining_uses
  • redemption_id

Prepaid passes

Prepaid products can hold counted visits, time-limited unlimited visits, or money for the issuing business. Templates are prepaid-passes; sold instances are member-passes. The calls below default to visit format 1. For money, use format 2.

List pass templates

GET /api/agent/v1/partner/prepaid-passes

Scope: read or write:passes

Get pass template

GET /api/agent/v1/partner/prepaid-passes/{id}

Scope: read or write:passes

Create pass template

POST /api/agent/v1/partner/prepaid-passes

Scope: write:passes

Set uses_total for a counted pass, or omit it and set validity_days (1 to 366) for an unlimited pass.

Update pass template

PUT /api/agent/v1/partner/prepaid-passes/{id}

Scope: write:passes

Delete pass template

DELETE /api/agent/v1/partner/prepaid-passes/{id}

Scope: write:passes

Soft-deletes the template so future sales stop. Passes already sold keep working.

Sell a pass

POST /api/agent/v1/partner/prepaid-passes/{id}/sell

Scope: write:passes

Issues a sold instance to a member. Body: member_identifier (required), optional price_paid (cents; defaults to the template price), optional staff_id (a staff member in the pass's club). With no staff attached, the ledger entry records source: agent_api plus the Integration API key id.

List a member's passes

GET /api/agent/v1/partner/members/{id}/passes

Scope: read or write:passes

Returns the member's sold passes in your clubs. Use it to find a member-pass id before scanning or undoing.

Get a sold pass

GET /api/agent/v1/partner/member-passes/{memberPassId}

Scope: read or write:passes

Returns the sold pass with its ledger history.

Scan a visit

POST /api/agent/v1/partner/member-passes/{memberPassId}/scan

Scope: write:passes

Deducts one or more visits. Body: optional quantity (default 1), optional staff_id. Counted passes lose quantity visits; unlimited passes record the visit only.

Undo the last visit

POST /api/agent/v1/partner/member-passes/{memberPassId}/undo

Scope: write:passes

Writes an offsetting ledger entry and restores the balance. Fails when there is no visit to undo.


Monetary passes

Add ?pass_format=2 to pass lists and detail calls to receive typed records. Without it, lists contain only visit passes and an owned monetary detail returns 409 MONETARY_PASS_FORMAT_REQUIRED. For an issued pass, format 2 includes balance_type, is_unlimited, and a money object with integer initial_minor, remaining_minor, reserved_refund_minor, and available_minor amounts plus currency. A null visit count never identifies an unlimited monetary pass. Invalid or empty formats return 422.

Monetary product writes and actions require both literal scopes, write:passes and write:pass-money. The admin scope alone does not suffice. Review the issuing Business details and fixed translated terms in the business dashboard, then enable monetary sales. Terms and retention periods are not editable. A monetary template uses balance_type: "money", an integer face_value_minor, and an equal price in the same currency. Follow the generated request schema; visit counts and validity must be null.

Record an external sale through the same /prepaid-passes/{id}/sell?pass_format=2 route. Supply the member identifier, payment_received: true, amount_minor, currency, terms_version, external_reference, and external_source. Record the payment at the counter or in the external payment system first. Reward Loyalty does not charge the member.

To spend €37.50 from a EUR pass:

POST /api/agent/v1/partner/member-passes/{memberPassId}/spend?pass_format=2
X-Agent-Key: rl_agent_...
Idempotency-Key: 6db65634-d279-4904-91e3-3fe56d0a825a
Content-Type: application/json

{
  "amount_minor": 3750,
  "currency": "EUR",
  "external_reference": "COUNTER-2026-0042",
  "external_source": "pos_receipt"
}

Amounts must be JSON integers in the currency's minor unit. A numeric string or a decimal is invalid. Keep the exact body and operation key after a timeout. A retry returns the recorded result after checking the current key and authority again. Reusing that key with a different body returns 409 IDEMPOTENCY_CONFLICT. A scoped 410 RECORD_REMOVED means an earlier consumed result is no longer available; never replace its key to repeat the financial action. Privacy removal can scrub a consumed result while preserving its financial history. The application does not age out monetary records or make their operation keys reusable after a retention period.

Reverse a complete spend with POST /partner/member-passes/{memberPassId}/transactions/{transactionId}/reverse?pass_format=2, a fresh Idempotency-Key, and reason_code set to entry_error or purchase_cancelled. The original spend can be reversed once. Visit /scan and /undo actions cannot change money balances.

Refund preparation, confirmation, cancellation, and financial-record corrections remain Partner/admin web actions. There are no payment-confirming Agent tools. See staff use and business oversight.

Tiers

Membership tiers define VIP levels with multipliers and benefits.

List tiers

GET /api/agent/v1/partner/tiers

Scope: read or write:tiers

Get tier

GET /api/agent/v1/partner/tiers/{id}

Scope: read or write:tiers

Create tier

POST /api/agent/v1/partner/tiers

Scope: write:tiers

Use the canonical tier threshold field: points_threshold.

Update tier

PUT /api/agent/v1/partner/tiers/{id}

Scope: write:tiers

Delete tier

DELETE /api/agent/v1/partner/tiers/{id}

Scope: write:tiers


Staff

Manage staff members who process transactions at partner locations.

List staff

GET /api/agent/v1/partner/staff

Scope: read or write:staff

Get staff member

GET /api/agent/v1/partner/staff/{id}

Scope: read or write:staff

Create staff member

POST /api/agent/v1/partner/staff

Scope: write:staff

Use the canonical staff assignment field: club_id.

Staff list/detail responses expose: id, club_id, club_name, name, email, locale, time_zone, number_of_times_logged_in, last_login_at, created_at, updated_at, avatar.

Update staff member

PUT /api/agent/v1/partner/staff/{id}

Scope: write:staff

Delete staff member

DELETE /api/agent/v1/partner/staff/{id}

Scope: write:staff


Apple Wallet settings

Method Endpoint Scope
GET /partner/apple-wallet/{type}/{id} read or write:wallet
PUT /partner/apple-wallet/{type}/{id} write:wallet

Use loyalty, stamp, offer, or prepaid for {type} and an owned item UUID for {id}. PUT accepts enabled and optional appearance settings; repeated identical requests return meta.result: "unchanged". These endpoints do not return signed member passes or signing credentials. See the Apple Wallet API for the fields, availability checks, and errors.