Subscription

subscription describes a recurring relationship between a payer and a payment method. The type below follows the fields serialized from the schema in the codebase.

Draft: The documented REST endpoints for subscription are not yet exposed in the router. Webhooks are the implemented integration path at the moment.

Payload

type SubscriptionID = `sub_${string}`;
type PaymentMethodType =
| "swish"
| "autogiro"
| "autogiro_external"
| "swish_external"
| "card"
| "card_external"
| "apple_pay"
| "apple_pay_external"
| "google_pay"
| "google_pay_external"
| "stripe_subscription"
| "sepa_direct_debit"
| "invoice"
| "none";

type PaymentChannel =
| "autogiro"
| "swish"
| "card"
| "apple_pay"
| "google_pay"
| "sepa_direct_debit";

type CollectedBy = "repejo" | "organisation";

type PaymentPeriod = {
time_period: "month" | "week" | "day";
period_interval: number;
dates_in_period: string[] | null;
};

type ProductType =
| "donation"
| "membership"
| "p2p"
| "onetime_donation"
| "gift_card"
| "memorial_card"
| "physical"
| "lottery"
| "face_to_face"
| "live";

type Subscription = {
id: SubscriptionID;
payer_id: PayerID;
amount: string;
transaction_date: string;
/** @deprecated Read payment_channel and collected_by instead. */
payment_method_type: PaymentMethodType;
payment_channel: PaymentChannel | null;
collected_by: CollectedBy | null;
payment_method: PaymentMethod | null;
status: "pending" | "active" | "signed" | "terminated";
reference: string;
source: "repejo" | "imported";
index_adjustment_consent: boolean;
metadata: Record<string, string>;
tracking: Record<string, string>;
valid_from: string;
payment_period: PaymentPeriod | null;
next_transaction_date: string | null;
terminated_at: string | null;
product_type: ProductType;
recruiter_external_id: string | null;
recruiter_first_name: string | null;
recruiter_last_name: string | null;
recruitment_method: string | null;
payer: Payer | null;
documents: {
  mandate_pdf_masked_url: string | null;
  mandate_pdf_unmasked_url: string | null;
  signature_xml_url: string | null;
};
};

documents holds authenticated API urls for the signed mandate PDFs and the BankID signature XML, or null where the document is never produced — see Payment Sessions.

amount is serialised as a string to preserve precision.

payment_channel is the payment method the donor chose, for example "autogiro" or "apple_pay". collected_by says who charges the later payments. The money always goes to your organisation's own account. "repejo" means that Repejo sends or registers the payment orders, or charges the stored card, and records the results. "organisation" means that your own setup charges, for example your Adyen integration, a subscription in your Stripe account or an external bankgiro. Repejo then starts no charge. Both are null while a pending subscription has no payment method. payment_channel is also null for an imported Stripe subscription whose payment method Repejo does not hold. payment_method is a nested object with type-specific details, or null when no payment method details are embedded. See PaymentMethod for the nested payload shape.

payment_method_type is deprecated. It joins the two fields above into one string: the _external values mean that the organisation collects. Use payment_channel and collected_by in new integrations. Repejo keeps sending payment_method_type unchanged.

recruiter_external_id is the external id of the recruiter (face-to-face fundraiser) attributed to the subscription, or null when no recruiter is attached. recruiter_first_name and recruiter_last_name are the recruiter's name, or null when no recruiter is attached. recruitment_method is the stable key of the recruitment method, or null.

valid_from is the time the subscription was created in Repejo. For a subscription imported into Repejo, it is the time of the import. payment_period says how often the donor gives, or is null when the subscription has no schedule. period_interval counts units of time_period between payments, so "month" with 1 is monthly, with 3 quarterly and with 12 yearly. dates_in_period holds the payment days, for example ["25"].

next_transaction_date is the date of the next charge when the event was sent. It is set while status is "active" or "signed" and collected_by is "repejo". It is null when collected_by is "organisation", because your own setup decides when it charges. When a charge moves the date, Repejo sends subscription.updated with the new date. An import of subscriptions in the back office changes the date without an event.

terminated_at is the time the subscription ended, or null while it runs. For a subscription that ended before 21 April 2026, it is the time of the last change to the subscription. A subscription with a fixed end date ends after its last charge, and Repejo then sends subscription.updated with status "terminated".

product_type says what the gift is for. A face-to-face gift has "donation". Read recruitment_method and the recruiter_* fields to find face-to-face gifts.

Repejo has no paused status. A paused subscription keeps status "active". The pause moves next_transaction_date to the date the donor gives again and sends subscription.updated.

Planned endpoints

  • GET /api/subscriptions
  • GET /api/subscriptions/:id
  • POST /api/subscriptions
  • PATCH /api/subscriptions/:id

In webhook payloads, the related payer is always embedded as a nested object for subscription events. It is null only when no payer is linked or the payer can no longer be loaded.