Payer

payer is Repejo's entity for a donor. The payload below reflects the fields currently serialized by the codebase.

Draft: The documented REST endpoints for payer currently exist as a planned contract. In the current router, webhooks are the implemented integration surface.

Common response format

type Response<T> = {
data: T;
};

Payload

type PayerID = `pay_${string}`;
type CheckoutID = `chk_${string}`;
type PayerPaymentMethod =
| "swish"
| "autogiro"
| "card"
| "apple_pay"
| "google_pay"
| "stripe_subscription"
| "sepa_direct_debit"
| "invoice"
| "none";

type Payer = {
id: PayerID;
name: string | null;
first_name: string | null;
last_name: string | null;
phone_number: string | null;
email: string | null;
status:
| "active"
| "pending"
| "rejected"
| "terminated"
| "aborted"
| "checkout"
| "completed"
| "petition_signer"
| "deleted"
| "archived";
/** @deprecated Read the method from the transaction or subscription. */
payment_method: PayerPaymentMethod;
contact_consent: boolean;
address_street: string | null;
address_zip: string | null;
address_city: string | null;
address_country: string | null;
personal_identity_number: string | null;
payer_type: "private" | "company";
company_name: string | null;
organisation_number: string | null;
note: string;
external_id: string | null;
reference_value: string | null;
reference_title: string | null;
metadata: Record<string, string>;
tracking: Record<string, string>;
preferred_locale: string;
checkout_id: CheckoutID | null;
anonymized_at: string | null;
inserted_at: string;
updated_at: string;
};

Every field above is always present in the payload; absent values are sent as null (not omitted). inserted_at and updated_at are naive timestamps without timezone (for example "2026-05-12T13:46:10").

For an Autogiro donor, status follows the mandate. When the donor signs, the payer is "pending" and the mandate goes to Bankgirot. If Bankgirot approves the mandate, the payer becomes "active" and you get payer.updated. If Bankgirot rejects it, the payer becomes "rejected" and you get payer.updated. A rejection is final for that mandate. When the organisation has its own (external) bankgiro connection, it activates the mandate by hand in Repejo, and that also sends payer.updated with "active". subscription.created is sent at signing, so it usually carries a "pending" payer.

payment_method is deprecated. It is not the payment method of a gift: it is "none" for a donor who only gave one-time gifts, and for a donor with several subscriptions it holds only one of their methods. Read the method of a gift from payment_method on the transaction or receivable, and the method of a recurring donation from payment_method_type on the subscription.

checkout_id links the payer to the checkout that created it. reference_value and reference_title carry the checkout reference captured for the payer. anonymized_at is null until an admin anonymizes the donor. Then it holds the time, and the personal fields are empty. The internal donor_portal_slug field is not included in webhook payloads.

tracking holds the marketing tags from the URL the checkout was opened on: every utm_* parameter plus fbclid, gclid, gbraid, wbraid and msclkid, at most 10 tags with values of at most 200 characters. On a payer it holds the tags of the first checkout that had any; on a subscription or receivable, the tags of the checkout that created it. It is an empty object when there were none.

payer_type tells you whether the donation is private or made by a company. For a "company" payer, company_name and organisation_number identify the company, while name, email and phone_number hold the contact person and the address_* fields hold the billing address. For a "private" payer, company_name and organisation_number are null.

Planned endpoints

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

If you build against the draft above, treat it as preliminary. The webhook page describes the part of the integration surface that actually delivers data today.