Receipts
A receipt records money for one or more attendances of one family: a payment taken at the counter, a payment made online, an invoice that is still open, or a reversal of an earlier receipt.
All receipt endpoints need ROLE_ADMIN and ROLE_PAYMENTS_ADMIN. Amounts are in cents; the items of a reversal are negative.
An invoice is not a separate resource: it's a receipt that hasn't been paid yet. You create a receipt open and pay it when the money comes in, or create it paid if you take the money at the counter right away.
The receipt model
- Name
uuid- Type
- string
- Description
The receipt's identifier.
- Name
receiptNumber- Type
- string
- Description
The receipt number: the organisation's prefix followed by a running number. Assigned when the receipt is paid, so an open invoice has none yet.
- Name
status- Type
- string
- Description
created(open: an invoice, or an online payment that hasn't gone through yet),paid,failedorabandoned. See the receipt workflow.
- Name
totalAmount- Type
- integer
- Description
The sum of the items, in cents.
- Name
createdAt- Type
- timestamp
- Description
When the receipt was created.
- Name
billingAddress- Type
- string
- Description
The billing address as printed on the receipt, one line per line. A placeholder when
piiMaskedistrue. Left out when the tenant encrypts the address: the API holds no key to read it.
- Name
billingEmail- Type
- string
- Description
The e-mail address the receipt goes to. A placeholder when
piiMaskedistrue.
- Name
paymentMethod- Type
- string
- Description
The name of the online payment method for online payments (
Online-Zahlungif it isn't known), andBargeldfor every other receipt, including open invoices and reversals.
- Name
debtor- Type
- object
- Description
The family's debtor: its
uuidand currentbalance.
- Name
account- Type
- reference
- Description
The account.
- Name
recordedBy- Type
- reference
- Description
Who created the receipt: the colleague who recorded it, or for online payments the family's own account. Missing for receipts created by a service account.
- Name
recordedByName- Type
- string
- Description
Who created the receipt, as the admin shows it: the name in
recordedBy, or{name} (Service-Account)for a service account, with the name it had at the time.
- Name
items- Type
- object[]
- Description
The lines of the receipt. Each has a
uuid, atype(attendancefor an attendance,discountfor balance used), anamount, and theattendanceUUID with itsofferandparticipantas references. Ondiscountlines these three arenull.
- Name
isReversal- Type
- boolean
- Description
Whether the receipt's total is negative, as a reversal's is. A reversal of
0(withholding 100 %) showsfalse; usereversalOfto be sure.
- Name
reversalOf- Type
- reference
- Description
The receipt this one reverses. The reference's
nameis its receipt number.
- Name
reversals- Type
- reference[]
- Description
Receipts that reverse this one, fully or in part.
- Name
canBeAdjusted- Type
- boolean
- Description
Whether this receipt can be adjusted: a paid, unreversed counter receipt. Always
falsewhenpiiMaskedistrue.
- Name
onlineTransactionId- Type
- string
- Description
The payment provider's transaction ID, for online payments.
- Name
transitions- Type
- string[]
- Description
The workflow transitions you can apply right now:
payandabandonfor an open receipt, none otherwise. Always empty whenpiiMaskedistrue.
- Name
piiMasked- Type
- boolean
- Description
truewhen the payer's details are hidden from you, so thatbillingAddressandbillingEmailhold placeholders. Such a receipt is read-only: it can be neither paid, abandoned, reversed nor adjusted. See Masked personal data.
The receipt workflow
A receipt starts open (created) and ends paid or abandoned. An open receipt is an invoice: the family owes the money, nothing is marked paid yet, and the receipt has no number. Apply a transition with POST /receipts/{uuid}/transition.
| Transition | From | To | What happens |
|---|---|---|---|
pay | created | paid | The money was taken. The receipt gets its number, the attendances are marked paid, and the balance it uses is taken from the family's debtor. |
abandon | created | abandoned | The receipt is dropped. The attendances stay unpaid. |
To take money at the counter in one step, create the receipt with "paid": true.
A receipt the family was sent a payment link for is open as well, and can be paid at the counter too. Once the family starts paying online, the receipt gets an onlineTransactionId and the payment provider moves it on to paid or failed: it has no transitions for you any more.
A paid receipt doesn't change state again. To give money back, reverse it; to correct it, adjust it.
/receiptsList all receipts
Returns a page of receipts, newest first.
Optional filters
- Name
q- Type
- string
- Description
Only receipts whose number, billing address or billing e-mail contains this text. Outside your own tenant, only the receipt number is searched. An encrypted billing address does not match.
- Name
status- Type
- string
- Description
Only receipts in this state:
created,paid,failedorabandoned.
- Name
account- Type
- string
- Description
Only receipts of this account (UUID, or e-mail address within your own tenant).
- Name
debtor- Type
- string
- Description
Only receipts of this debtor (UUID).
- Name
participant- Type
- string
- Description
Only receipts covering an attendance of this participant (UUID).
- Name
attendance- Type
- string
- Description
Only receipts covering this attendance (UUID).
- Name
edition- Type
- string
- Description
Only receipts covering attendances in this edition (UUID or alias).
- Name
reversals- Type
- boolean
- Description
truefor reversals only,falseto leave them out.
- Name
createdSince- Type
- timestamp
- Description
Only receipts created since this moment.
- Name
page, itemsPerPage- Type
- integer
- Description
See Pagination.
curl -G https://example.fepli.eu/api/receipts \
-H "Authorization: Bearer $FEPLI_TOKEN" \
--data-urlencode "account=familie.mueller@example.org"
Response
[
{
"uuid": "0192e1a0-7b8c-7d9e-a0f1-2b3c4d5e6f08",
"receiptNumber": "RE-142",
"status": "paid",
"totalAmount": 1250,
"createdAt": "2026-09-10T10:22:31+02:00",
"billingAddress": "Anna Müller\nLindenallee 12\n12345 Elmsbrück",
"billingEmail": "familie.mueller@example.org",
"paymentMethod": "Bargeld",
"debtor": {
"uuid": "0191c7b4-5a6b-7c8d-9e0f-1a2b3c4d5e09",
"balance": 0
},
"account": {
"uuid": "0191c7b2-4d5e-7f60-8a1b-2c3d4e5f6a05",
"name": "Anna Müller"
},
"recordedBy": {
"uuid": "0190a1b2-c3d4-7e5f-8a6b-7c8d9e0f1a22",
"name": "Sabine Krüger"
},
"recordedByName": "Sabine Krüger",
"items": [
{
"uuid": "0192e1a0-8c9d-7e0f-a1b2-c3d4e5f6a724",
"type": "attendance",
"amount": 750,
"attendance": "0192d0e8-3a4b-7c5d-9e6f-7a8b9c0d1e07",
"offer": {
"uuid": "0192a4f1-6e3b-7c85-b1d2-8f4e6a9c3b03",
"name": "Fahrradtour durch den Stadtpark",
"alias": "fahrradtour-durch-den-stadtpark"
},
"participant": {
"uuid": "0191c7b3-1f2a-7c4d-8e5f-6a7b8c9d0e06",
"name": "Lena Müller"
}
},
{
"uuid": "0192e1a0-9dae-7f10-b2c3-d4e5f6a7b825",
"type": "attendance",
"amount": 500,
"attendance": "0192d0f1-4b5c-7d6e-8f7a-9b0c1d2e3f23",
"offer": {
"uuid": "0193c8a2-5d6e-7f70-9a8b-1c2d3e4f5a14",
"name": "Töpfern für Anfänger",
"alias": "toepfern-fuer-anfaenger"
},
"participant": {
"uuid": "0191c7b3-2e3f-7a4b-9c5d-6e7f8a9b0c16",
"name": "Paul Müller"
}
}
],
"isReversal": false,
"reversals": [],
"canBeAdjusted": true,
"transitions": [],
"piiMasked": false
}
]
/receipts/{uuid}Retrieve a receipt
Returns one receipt.
curl https://example.fepli.eu/api/receipts/0192e1a0-7b8c-7d9e-a0f1-2b3c4d5e6f08 \
-H "Authorization: Bearer $FEPLI_TOKEN"
/receiptsCreate a receipt
Creates a receipt for one or more open attendances of one family. By default, the receipt is open: an invoice, the Rechnung of the admin. Nothing is marked paid until you apply pay.
With "paid": true, the receipt records money taken at the counter, like Zahlung erfassen in the admin: the attendances are marked paid and the receipt gets its number right away.
- All attendances must belong to the same family, be unpaid, and be in an edition that collects fees through fepli.
- If you read the family's details masked, with or without an account, the answer is
403. - If the family's debtor has a positive
balance, it is used first (as adiscountitem) unless you send"useBalance": false. Only the part that no other open receipt already sets against its fees is used, so the amount can be lower than thebalance. - If an item's amount is less than the fee, the rest is booked as a claim on the family's debtor when the receipt is paid (for participants with an account).
Required attributes
- Name
items- Type
- object[]
- Description
The attendances on the receipt: objects with
attendance(UUID) and optionallyamountin cents, from0up to the fee. Withoutamount, the full fee is charged.
Optional attributes
- Name
paid- Type
- boolean
- Description
The money was taken at the counter: the receipt is paid right away. Defaults to
false, an open receipt.
- Name
useBalance- Type
- boolean
- Description
Use the family's balance, less what other open receipts already hold. Defaults to
true.
- Name
billingAddress- Type
- string
- Description
The billing address as printed on the receipt. Defaults to the account's address, or else the participant's. A tenant that encrypts stores it encrypted; later reads leave it out.
- Name
billingEmail- Type
- string
- Description
Where the receipt is sent. Defaults to the account's e-mail address.
- Name
notify- Type
- boolean
- Description
E-mail the receipt to the family. Defaults to
false. Needspaid.
curl -X POST https://example.fepli.eu/api/receipts \
-H "Authorization: Bearer $FEPLI_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "attendance": "0192d0e8-3a4b-7c5d-9e6f-7a8b9c0d1e07" },
{ "attendance": "0192d0f1-4b5c-7d6e-8f7a-9b0c1d2e3f23" }
]
}'
Response (201 Created, excerpt)
{
"uuid": "0193d2b4-6c7d-7e8f-9a0b-1c2d3e4f5a26",
"receiptNumber": null,
"status": "created",
"totalAmount": 1250,
"…": "…",
"transitions": ["pay", "abandon"]
}
/receipts/{uuid}/transitionApply a transition
Moves an open receipt through its workflow: pay when the money has been taken, abandon when the receipt is no longer needed. The receipt's transitions list the ones possible right now. Anything else is a 409 that names the possible transitions, and so is any transition on an online payment. For a receipt with piiMasked set to true, the answer is 403.
Before pay, the receipt is checked against what happened since it was created. If one of its attendances was paid in the meantime, or the part of the family's balance that no other open receipt holds no longer covers what the receipt takes from it, the answer is 409: abandon the receipt and create a new one.
Required attributes
- Name
transition- Type
- string
- Description
payorabandon.
Optional attributes
- Name
notify- Type
- boolean
- Description
For
pay: e-mail the receipt to the family. Defaults tofalse.
curl -X POST https://example.fepli.eu/api/receipts/0193d2b4-6c7d-7e8f-9a0b-1c2d3e4f5a26/transition \
-H "Authorization: Bearer $FEPLI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"transition": "pay", "notify": true}'
Response (excerpt)
{
"uuid": "0193d2b4-6c7d-7e8f-9a0b-1c2d3e4f5a26",
"receiptNumber": "RE-158",
"status": "paid",
"totalAmount": 1250,
"…": "…",
"canBeAdjusted": true,
"transitions": []
}
/receipts/{uuid}/reverseReverse a receipt
Reverses a paid receipt, fully or in part, and returns the new reversal receipt. By default, the attendances are marked unpaid again and the money is paid out. The reversal receipt is e-mailed to the billing address, as in the admin. If the original's billing address is encrypted, the reversal receipt has an empty one.
Only paid receipts can be reversed, and a reversal can't be reversed itself (409). An open receipt has nothing to reverse: abandon it instead. Attendances that were already reversed and marked unpaid are skipped; if nothing is left to reverse, the answer is 409. For a receipt with piiMasked set to true, the answer is 403: the reversal would copy the placeholders into a new receipt.
Optional attributes
- Name
items- Type
- string[]
- Description
The item UUIDs to reverse. Leave it out to reverse every attendance on the receipt.
- Name
partial- Type
- object
- Description
Reverse less than the full amount.
{"type": "percent", "value": 20}withholds 20 % and reverses the other 80 %, for example to keep a cancellation fee.{"type": "amount", "value": 1250}reverses exactly 1250 cents. Leave it out to reverse the full amount.
- Name
payout- Type
- string
- Description
Where the money goes:
payout(handed back, the default) orbalance(added to the family's balance for later use).
- Name
unpay- Type
- boolean
- Description
Mark the attendances unpaid again. Defaults to
true. Sendfalseif the money was returned for another reason and the attendances stay paid.
- Name
withdraw- Type
- boolean
- Description
Also withdraw the attendances. Defaults to
false.
curl -X POST https://example.fepli.eu/api/receipts/0192e1a0-7b8c-7d9e-a0f1-2b3c4d5e6f08/reverse \
-H "Authorization: Bearer $FEPLI_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"items": ["0192e1a0-8c9d-7e0f-a1b2-c3d4e5f6a724"],
"payout": "balance",
"withdraw": true
}'
Response (excerpt)
{
"uuid": "0193d3c5-7d8e-7f90-8a1b-2c3d4e5f6a27",
"receiptNumber": "RE-157",
"status": "paid",
"totalAmount": -750,
"isReversal": true,
"reversalOf": {
"uuid": "0192e1a0-7b8c-7d9e-a0f1-2b3c4d5e6f08",
"name": "RE-142"
},
"items": [
{
"uuid": "0193d3c5-8e9f-7a01-9b2c-3d4e5f6a7b28",
"type": "attendance",
"amount": -750,
"attendance": "0192d0e8-3a4b-7c5d-9e6f-7a8b9c0d1e07",
"…": "…"
}
],
"…": "…"
}
/receipts/{uuid}/adjustAdjust a receipt
Corrects a counter receipt, for example when the wrong amount was entered. The original receipt is reversed in full and a new one is issued with the items, address and e-mail you send. Returns the new receipt.
Only paid, unreversed counter receipts can be adjusted: check canBeAdjusted. Otherwise the answer is 409. For a receipt with piiMasked set to true, the answer is 403, even if the request sends a new address.
Required attributes
- Name
items- Type
- object[]
- Description
The items of the new receipt: objects with
attendance(UUID, one of the original receipt's attendances) andamountin cents.
Optional attributes
- Name
billingAddress- Type
- string
- Description
The billing address. Defaults to the original receipt's. If the original's address is encrypted, the default is empty: send the address to keep it.
- Name
billingEmail- Type
- string
- Description
The e-mail address. Defaults to the original receipt's.
- Name
paid- Type
- boolean
- Description
Mark the new receipt paid. Defaults to
true. Withfalse, the new receipt stays open until youpayit.
- Name
notify- Type
- boolean
- Description
E-mail the new receipt. Defaults to
false. Needspaidand abillingEmailin the request.
curl -X POST https://example.fepli.eu/api/receipts/0192e1a0-7b8c-7d9e-a0f1-2b3c4d5e6f08/adjust \
-H "Authorization: Bearer $FEPLI_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "attendance": "0192d0e8-3a4b-7c5d-9e6f-7a8b9c0d1e07", "amount": 750 },
{ "attendance": "0192d0f1-4b5c-7d6e-8f7a-9b0c1d2e3f23", "amount": 250 }
]
}'