Skip to content
Last updated

Intro

Use case description of how to use the online offers collection to retrieve, display, and sell digital products and services via the Open API.

This collection supports the full purchase lifecycle:

  • Display a catalog of available offers.
  • Show per-offer details and generate a transparent purchase preview.
  • Execute the purchase and provision the service to the customer's account.
  • Retrieve a customer's purchase history by offer or account.

Relevant Endpoints

Online offers

The online offers collection exposes the product catalog and purchase flow for digital goods to third-party integrations.

Core behavior:

  • Offers are only returned if active, within their valid publication period, and configured as available for online purchase.
  • Each offer defines validity periods, usage scope, and applicable access restrictions.
  • Prices and applicable tax rates are determined per offer and surfaced in the preview step.
  • Studio access restrictions may limit offer visibility or purchasability to specific locations.

Recommended use cases:

  • Direct purchase flows in member-facing web or app
  • Partner-embedded e-commerce (course passes, entry packs, time-based access)
  • Pre-purchase price transparency with voucher validation
  • Post-purchase history display and entitlement tracking

Display, preview, and purchase flow

1. Retrieve the offers catalog

Use GET online offers to return a list of all purchasable offers visible to the integration.

Use this to:

  • render the offer catalog in your UI
  • filter or sort offers by type, validity, or price
  • determine which offers are currently active and available

2. Get offer details

Use GET online offer details for any offer the customer selects.

Use this to:

  • display per-offer terms (validity period, usage scope, access restrictions)
  • inform the customer before any pricing step

3. Generate a purchase preview

Use POST online offer purchase preview to calculate and display the final price before the customer commits.

Use this to:

  • show a transparent cost breakdown including taxes
  • validate and apply voucher codes before checkout
  • surface eligibility issues early without initiating a transaction

Voucher code handling: pass the voucher code in the preview request so the system can validate code status (active, expired, usage limit reached), studio and offer applicability, and customer eligibility. A valid preview response includes basePrice, discountedBasePrice, voucherDiscount (Money objects), and a voucherSuccessMessage. If invalid, the response returns a voucherErrorCode. The same voucher context must be passed in the purchase request. Integrations should handle invalid or ineligible codes with explicit user feedback.

4. Execute the purchase

Use POST purchase an online offer once the customer confirms.

Use this to:

  • provision the service to the customer's account
  • retrieve the studioAccessCode returned on success for gym entry

Best practice:

  • revalidate voucher context at purchase time to guard against stale or concurrently reused codes
  • when a voucher code is applied, always request the payment token using the discountedBasePrice from the preview response, not the original basePrice — the payment must reflect the final amount the customer is charged
  • store the returned studioAccessCode and look up the onlineOfferPurchaseId via the purchase history endpoints for support and reporting

5. Retrieve purchase history

Use GET online offer purchases by customer id for a full account-level purchase list.

Use GET online offer purchases by customer id and offer id to narrow the history to a specific product.

Use this to:

  • display active entitlements and past purchases in a customer account view
  • resolve support questions about specific purchased offers

Complete workflow examples

Note: The payload examples below are integration-oriented drafts. Validate all field names and structures against the current OpenAPI schema before publishing or implementation.

Example 1: Direct purchase with voucher

Scenario: Customer selects a 10-entry pass, applies a voucher, and completes checkout.

  1. GET online offers
  2. GET online offer details
  3. POST online offer purchase preview (with voucher code)
  4. Show confirmed price to customer
  5. POST purchase an online offer (with same voucher context)

Example preview request payload (illustrative):

{
  "onlineOfferId": 12345,
  "customerId": 67890,
  "voucherCode": "SUMMER21"
}

Example preview response shape (illustrative):

{
  "basePrice": {
    "amount": 40.00,
    "currency": "EUR"
  },
  "discountedBasePrice": {
    "amount": 32.00,
    "currency": "EUR"
  },
  "voucherDiscount": {
    "amount": 8.00,
    "currency": "EUR"
  },
  "voucherSuccessMessage": "Voucher applied successfully"
}

Example purchase payload (illustrative):

{
  "onlineOfferId": 12345,
  "customerId": 67890,
  "validFrom": "2024-07-01",
  "voucherCode": "SUMMER21",
  "paymentRequestToken": "abc123token"
}

Example purchase response shape (illustrative):

{
  "studioAccessCode": "PTKXPMUO",
  "voucherSuccessMessage": "Voucher applied successfully"
}

Example 2: Purchase history lookup

Scenario: Customer requests a list of their active and past purchases.

  1. GET online offer purchases by customer id
  2. Render purchase list with status and expiry

To narrow to a specific offer (e.g., for entitlement check):

  1. GET online offer purchases by customer id and offer id

Common integration challenges

  • Skipping the preview step: Always generate a purchase preview before executing a transaction. This is the primary price and eligibility validation point.
  • Stale voucher context: Voucher codes must be revalidated at purchase time. A code valid during preview may expire or be consumed before the purchase request lands.
  • Missing access restriction handling: Studio restrictions can silently exclude offers from catalog results. Verify studio context if expected offers are absent.
  • No post-purchase state refresh: Re-fetch purchase history after a successful transaction to keep UI entitlement state current.
  • Missing purchase record storage: Persist the studioAccessCode immediately after purchase and retrieve the onlineOfferPurchaseId from purchase history for auditing and support resolution.

Online offers webhook events

Online offer purchases emit three webhook events that together cover the full payment lifecycle.

Event lifecycle

EventWhen it fires
CUSTOMER_ONLINE_OFFER_CREATEDThe purchase record is created and the contingent is provisioned. Fires immediately on successful purchase, before payment is confirmed by the payment provider.
CUSTOMER_ONLINE_OFFER_PAYMENT_CAPTUREDThe payment for the purchase has been successfully captured by the payment provider.
CUSTOMER_ONLINE_OFFER_PAYMENT_REJECTEDThe payment was rejected by the payment provider. The purchase is fully reversed.

CUSTOMER_ONLINE_OFFER_CREATED and CUSTOMER_ONLINE_OFFER_PAYMENT_CAPTURED carry the same payload shape:

{
  "offerId": 1250918950,
  "offerPurchaseId": 1250919341
}

All three events scope the entity to the customer: entityId is the customerId.

Event reference:

Online sale reversal handling

When a payment for an online offer purchase is rejected, initiates a full reversal of the purchase. This closes the related open claim so the same offer can be purchased again without leaving residual debt behind. Partners are notified through the CUSTOMER_ONLINE_OFFER_PAYMENT_REJECTED webhook.

The following are reversed as part of this process:

  • Purchased contingent
  • Timeline entries
  • Invoices
  • Voucher redemption (if a voucher was applied at the time of purchase)
  • Online sales are marked as reversed

Because the purchased contingent is hard-deleted during reversal, the data would otherwise be permanently lost. For this reason, the CUSTOMER_ONLINE_OFFER_PAYMENT_REJECTED webhook carries a rich payload containing the full offer purchase details captured at the time of rejection. Integrations that store or act on purchase data should subscribe to this event and use the payload to reconcile their records.

Partial usage limitation

The current reversal flow does not account for partially used benefits. If a benefit was used before the payment was rejected, that usage is not reconstructed during reversal.

CUSTOMER_ONLINE_OFFER_PAYMENT_REJECTED payload:

{
  "offerPurchaseId": 1250919341,
  "offerId": 1250918950,
  "name": "MODIFIED-onlineOfferUseCase",
  "category": {
    "id": 1210001531,
    "name": "analysis"
  },
  "scopeOfUsage": 5,
  "price": {
    "amount": "99.00",
    "currency": "EUR"
  },
  "discountValue": {
    "amount": "5.00",
    "currency": "EUR"
  },
  "discountedPrice": {
    "amount": "94.00",
    "currency": "EUR"
  },
  "studioId": 1210086760,
  "studioAccessCode": "PCTQFT97",
  "purchaseDate": "2026-06-16T17:27:59+02:00",
  "validFrom": "2026-06-16T00:00:00+02:00",
  "expiryDate": "2026-07-16T00:00:00+02:00",
  "voucherCode": "CHVJP-UE2K-PKRX",
  "paymentTransactionId": 1250919271,
  "rejectionReason": null
}