Architecture

The CatalystPay Payment Session API is built around a clear hierarchy of commerce entities. Understanding how these entities relate to each other will help you design your integration and interpret the data you receive through webhooks and the reconciliation API.

Data hierarchy

Entity descriptions

Campaign

A Campaign is the top-level organizational unit for a payment funnel. It ties together an offer, a payment mode (SEPA Direct Debit, Credit Card, or Open Banking), session settings like maximum payment attempts, and duplicate lead handling rules.

Campaigns also link to Hosted Pages for branded payment page configuration and to Webhook Profiles for event notification routing.

Offer

An Offer combines a product with pricing and billing configuration. It defines:

  • Price and currency -- How much the customer pays (e.g., EUR 29.99)
  • Billing type -- ONE_OFF, RECURRING, or TRIAL_RECURRING
  • Billing frequency -- For recurring offers: WEEKLY, BIWEEKLY, MONTHLY, QUARTERLY, SEMIANNUALLY, or YEARLY
  • Trial settings -- Trial interval unit (day, week, month), trial period duration, and trial price
  • Payment gateway -- Which gateway (MID) processes payments for this offer

Payment Session

A Payment Session tracks the lifecycle of a single checkout attempt. When you call POST /api/v1/payment-sessions/, CatalystPay creates a session and returns a token. That token follows the session through payment submission, optional mandate verification, and completion or failure.

Session statuses:

Status Meaning
PENDING Session created, awaiting payment
PAYMENT_IN_PROGRESS Payment submission in flight
AWAITING_VERIFICATION Customer must complete mandate signing
COMPLETED Payment approved
FAILED All retry attempts exhausted
EXPIRED Session cancelled before payment

Terminal states (COMPLETED, FAILED, EXPIRED) cannot transition to any other state.

Lead

A Lead is the customer identity, uniquely identified by IBAN. Leads are created automatically when a payment session is created (or matched to an existing lead by email within the campaign scope). A lead carries:

  • Name, email, phone
  • IBAN and BIC
  • Address (street, city, postal code, country as ISO 3166-1 alpha-2)
  • Lifecycle status: LEAD -> ACTIVE_CUSTOMER -> CHURNED or CHARGEDBACK

Order

An Order is the purchase record created when a payment session completes successfully. It captures the amount, currency, and links to the lead, campaign, offer, and payment gateway. Orders have their own status lifecycle:

Status Meaning
PENDING_PAYMENT_SUBMISSION Order created, payment not yet submitted
PENDING Payment submitted, awaiting confirmation
COMPLETED Payment approved
FAILED Payment declined
PARTIALLY_REFUNDED Partial refund issued
REFUNDED Full refund issued
CHARGEDBACK Customer disputed the payment
CANCELLED Order cancelled

Subscription

A Subscription is created when the purchased offer has a RECURRING or TRIAL_RECURRING billing type. It tracks the billing schedule, next billing date, and revenue counters. Subscription statuses:

Status Meaning
PENDING_ACTIVATION Awaiting first successful charge
ACTIVE Billing on schedule
PENDING Pending first payment
PAST_DUE Missed a billing cycle
PAUSED Temporarily suspended
CANCELLED Subscription cancelled
EXPIRED Subscription term ended
CHARGEDBACK Customer disputed a charge
FAILED Subscription creation failed

Transaction

A Transaction is the financial event record. Every payment attempt, rebill, and refund creates a transaction. Transactions carry standardized statuses and types that are consistent across all payment gateways:

Statuses: approved, declined, pending_async, pending_hold, pending, error, refunded, cancelled, charged_back, voided, chargeback_reversed, represented, representment_reversed, second_chargeback, pending_review, partially_reversed, other_status (unmapped adapter status), pending_payment_submission (transaction created, not yet submitted to processor)

Types: sdd_sale (Direct Debit sale), sdd_refund (Direct Debit refund), other_type (unmapped adapter transaction type)

Chargeback

A Chargeback is a dispute record linked to the original transaction. It carries the report date (when the chargeback was reported), the transaction date (when the original payment occurred), the reason code, and the dispute amount.

Campaign mode vs direct mode

CatalystPay provides two ways to create payment sessions, depending on who owns the product catalog.

Campaign mode

When you pass a campaign_id in the session creation request, CatalystPay resolves the entire payment context automatically:

The campaign acts as a bundle that ties together everything needed for a payment: which product is being sold, at what price, through which gateway, with what billing schedule, how the hosted page should look, and where to send webhooks.

Choose Campaign mode when:

  • You use the CatalystPay admin UI to manage products and pricing
  • You want hosted payment pages with branded content
  • You have multiple campaigns with different offers, gateways, or branding
  • Operational teams need to change pricing without code deployments

Direct mode

When campaign_id is omitted, CatalystPay enters direct mode. You must supply four fields that would otherwise come from the campaign chain:

  • gateway_id -- Which payment gateway to use
  • amount -- The payment amount
  • currency -- The currency code (ISO 4217)
  • billing_type -- ONE_OFF, RECURRING, or TRIAL_RECURRING

Choose Direct mode when:

  • Your system already manages products, prices, and billing schedules
  • You treat CatalystPay as a payment processing API, not a commerce platform
  • You need maximum control over every parameter in each request
  • You are building a server-to-server integration

Pricing overrides

Even in Campaign mode, you can override pricing on a per-session basis by passing optional fields like amount, currency, billing_type, and billing_frequency. These override the campaign's offer values for that session only, without changing the underlying configuration.

This is useful for promotional discounts, currency conversion, A/B testing, or trial customization.

In Direct mode, the Order's campaign and offer fields are null. Webhook routing falls back to an explicit webhook_profile_id rather than the campaign's webhook profile. If you need webhooks in Direct mode, pass a webhook_profile_id when creating the session.

The status cascade

When a transaction's status changes, related entities are automatically recalculated:

The cascade follows a priority hierarchy:

  1. CHARGEDBACK (highest) -- Any chargeback makes the lead CHARGEDBACK
  2. ACTIVE_CUSTOMER -- Any active subscription or completed standalone order
  3. CHURNED -- Only terminal subscriptions remain
  4. LEAD (default) -- No payment history

This means a single chargeback cascades through the entire entity chain: transaction, order, subscription, and lead.

Next steps