Funding Receipt
org.hypercerts.funding.receipt
Overview#
A funding receipt describes a payment: who received it, and optionally how much, who sent it, what kind of payment it was, which intermediary handled it, when it happened, how it was transferred, and which activity, project, or organization it supported.
Receipts connect support to the work it funded, so a later reader can see who backed a project alongside its evidence and assessments. That history is also a trust signal for the next funder. A receipt describes a payment; it doesn't move money or prove that money arrived. Funds move through whatever payment system the platform or funder uses, and the receipt records it afterwards. For the concepts, see Funding and Learning in the Guide.
How it's used#
- A platform records payments it facilitated. A crowdfunding or grants platform publishes a receipt from its own account for each payment, naming the funder in
fromand the project into. - Funders and recipients record their own. A funder can publish receipts for grants it made, or a recipient for support it received.
- Receipts point to the work.
forlinks the payment to the activity, project collection, or organization it supported. - Named parties confirm. The funder or recipient can publish an acknowledgement of a receipt someone else wrote, adding their own confirmation.
- Applications show funding history. Receipts don't appear on the activity itself. An application finds them through an indexer, by looking for receipts whose
forpoints to the activity.
Only to and createdAt are required. amount and currency are optional, so a receipt can still be written when only the amount received is known. Parties can be named by DID, by a strong reference to a record, or by free text, so receipts work even when a party has no account.
Schema#
Record key: tid · Lexicon version: 1.6.0 · View the schema
Required properties#
| Property | Type | Description |
|---|---|---|
to | union: text, app.certified.defs#did, strongRef | The recipient of the funds (a free-text string, an account DID, or a strong reference to a record). |
createdAt | string (datetime) | Client-declared timestamp when this receipt record was created. |
Optional properties#
| Property | Type | Description |
|---|---|---|
from | union: text, app.certified.defs#did, strongRef | The sender of the funds (a free-text string, an account DID, or a strong reference to a record). Optional — omit to represent anonymity. Name a sender only if they chose to be named: from can be added later by updating the receipt in place, but removing it later only hides the name from the current version, and an onchain transactionId still names the sending wallet. |
via | union: text, app.certified.defs#did, strongRef | Optional intermediary that facilitated or processed the payment (funding platform, payment servicer, broker). |
type | string | What the payment is: a donation (a gift from the sender), a match (funds a matching pool allocated on the strength of other gifts) or a grant (funds awarded through a selection process). Values beyond the known set are permitted. Omit if unknown. maxLength: 50 Known values: donation, match, grant. |
amount | string | Gross amount the sender paid, before fees, as a numeric string (e.g. '1000.50'). Omit if unknown, and set netAmount instead. maxLength: 50 |
currency | string | Currency of amount: an ISO 4217 code for fiat (e.g. EUR), a token ticker for digital assets (e.g. USDC). This is what marks the funds as fiat or digital. Set it whenever amount is set. maxLength: 10 |
netAmount | string | What the recipient received after fees and conversion, as a numeric string in netCurrency. maxLength: 50 |
netCurrency | string | Currency of netAmount: an ISO 4217 code for fiat, a token ticker for digital assets. Set it whenever netAmount is set. maxLength: 10 |
paymentRail | string | How the sender paid. Use 'payment_processor' only when the underlying method is unknown. maxLength: 50 Known values: onchain, bank_transfer, card, direct_debit, mobile_money, payment_processor, cash, check. |
paymentNetwork | string | Where transactionId can be looked up: the chain for onchain payments, preferably as a CAIP-2 ID (e.g. 'eip155:1'), otherwise the processor or scheme (e.g. stripe, sepa). Set it whenever transactionId is a transaction hash. maxLength: 50 |
transactionId | string | ID of the sender's payment, not of a platform's later payout: a transaction hash for onchain payments, otherwise the processor's or scheme's reference. Receipts are public: prefer opaque processor IDs to bank references, and note that a hash reveals the sender's wallet even when from is omitted. maxLength: 256 |
for | strongRef | Optional strong reference to the activity, project, or organization this funding relates to. |
notes | string | Optional notes or additional context for this funding receipt. maxLength: 500 |
occurredAt | string (datetime) | Timestamp when the payment occurred. |
signatures | app.certified.signature.defs#list | Optional cryptographic signatures attesting to this record's content. |
Definitions#
text
A free-text string value (e.g. a display name, wallet address, or other identifier).
| Property | Type | Required | Description |
|---|---|---|---|
value | string | Yes | The string value. maxLength: 2048 |
Example#
A funding platform records a matched contribution from a funder to the community energy project's installation phase. The platform publishes the receipt from its own account, so the funder and the project are named parties, not the publisher:
{
"$type": "org.hypercerts.funding.receipt",
"from": {
"$type": "app.certified.defs#did",
"did": "did:plc:t6hz3bqk7wmx2nrv5ydc4lpe"
},
"to": {
"$type": "app.certified.defs#did",
"did": "did:plc:4yyb5gyoxl3sqdlqrvuxshkp"
},
"via": {
"$type": "app.certified.defs#did",
"did": "did:plc:ragtjsm2j2vknwkz3zp4oxrd"
},
"type": "match",
"amount": "2500.00",
"currency": "EUR",
"netAmount": "2475.00",
"netCurrency": "EUR",
"paymentRail": "bank_transfer",
"paymentNetwork": "sepa",
"transactionId": "SEPA-TX-7Q4K9M2X8P",
"for": {
"uri": "at://did:plc:4yyb5gyoxl3sqdlqrvuxshkp/org.hypercerts.claim.activity/3lxa4m2vbqk2s",
"cid": "bafyreif3kq7xmzd2vhw5l4yjn6rb2pc7tsgoe4ua5xi3qhk6wzdmfv2nle"
},
"notes": "Matched contribution from the summer community energy round.",
"occurredAt": "2026-07-20T10:05:00.000Z",
"createdAt": "2026-07-20T10:12:00.000Z"
}
Rules and best practices#
- The publisher and the named parties are different things. A receipt is the statement of the account that published it. Naming a funder in
fromand a recipient intodoesn't show that either agrees. Applications show who published a receipt alongside the parties it names, and treat an acknowledgement from a named party as additional confirmation. - A receipt doesn't prove payment. Validation checks structure, not whether the payment happened.
transactionIdwithpaymentRailandpaymentNetworklets someone check the payment against the rail's own records. A signature attests to the record's content, not to the transfer of funds. - Name parties by DID when you can. Use the DID variant for any party with an AT Protocol account, so readers can look for that party's acknowledgement. Use free text (
#text) only for parties without an account, such as a wallet address or an organization's name, and don't write a DID or handle into a free-text value. - Omit
fromfor anonymous senders. Leave the property out entirely rather than writing a placeholder such as "anonymous". Omitting it hides the sender only when someone other than the sender publishes the receipt, and an onchaintransactionIdstill reveals the sending wallet. - Name a sender only if they chose to be named.
fromcan be added later by updating the receipt. Removing it later hides the name only from the current version: readers and indexers that kept an earlier version still have it. - Separate gross from net.
amountis the gross the sender paid, before fees.netAmountis what the recipient received after fees and conversion, innetCurrency. Set whichever you know. If only the received amount is known, omitamountand setnetAmount. Always set the matching currency. - Say what kind of payment it is.
typeisdonation(a gift from the sender),match(funds a matching pool allocated because of other gifts), orgrant(funds awarded through a selection process). Other values are allowed; omit it if unknown. - Name the intermediary in
via.viais the funding platform, payment servicer, or broker that facilitated or processed the payment. It is separate from the publisher: a platform can be named inviaon a receipt someone else publishes. - Record payments through intermediaries by who chose the recipient. If the sender chose the recipient, publish one receipt from sender to final recipient, even when platforms or fiscal hosts passed the funds on. If the intermediary chose the recipient (regranting), publish one receipt for the payment into the intermediary and a separate receipt for each onward payment.
- Write amounts in the currency's normal unit. Use a plain decimal string such as
"2500.00"foramountandnetAmount, in euros rather than cents and in ETH rather than wei. There is no field for scale, so a value in the smallest unit is indistinguishable from one many times larger. - Be precise about currency.
currencyhas no fixed vocabulary. For fiat money, the ISO 4217 code (EUR,USD) is the clearest choice. For digital assets, give the token ticker (such asUSDC) and setpaymentNetwork, because one ticker can mean different assets on different networks. - Describe how and where it was paid.
paymentRailsays how the sender paid. Known values areonchain,bank_transfer,card,direct_debit,mobile_money,payment_processor,cash, andcheck; usepayment_processoronly when the underlying method is unknown.paymentNetworksays wheretransactionIdcan be looked up: for onchain payments, the chain, preferably as a CAIP-2 ID such aseip155:1; otherwise the processor or scheme, such asstripeorsepa. - Treat
transactionIdas public. Use the ID of the sender's payment, not of a platform's later payout. Prefer opaque processor IDs to bank references, and remember that an onchain hash reveals the sender's wallet even whenfromis omitted. - Set
occurredAt.createdAtis when the record was written, which can be days or months after the payment. UseoccurredAtto place a payment in a reporting period. - Link to the work with
for. It is the only property connecting a receipt to what it funded. Don't infer the funded work fromnotesor from the publisher's other records.forholds one reference, so a payment split across several activities is recorded as one receipt per activity, each with its share asamountand the sametransactionId. - Correct in place, and don't duplicate. Fix a mistake or add details by updating the existing receipt under the same record key, not by publishing a corrected copy alongside it. References by URI keep resolving, but strong references (such as likes and reposts) still pin the earlier version, and signatures must be renewed because they bind to the content. When another party has already recorded a payment, acknowledging their receipt adds confirmation without creating a second record that could be double counted.
- Aggregate totals honestly. One payment can have several receipts from different publishers, and anyone can publish receipts. Before summing, deduplicate receipts that describe the same payment allocation: the same
transactionIdandpaymentNetworkand the samefortarget. Keep receipts with distinctfortargets, since one payment split across several activities shares atransactionId. Also don't assume every receipt has anamount, don't mix grossamountwithnetAmount, don't add amounts in different currencies without stating the conversion rate and date, and decide which publishers to include. Show readers which receipts a total covers, and don't present it as all the funding a project received: no application can see every receipt on the network.
Related#
- Activity Claim, Collection, and Organization: what a receipt's
fortypically points to. - Acknowledgement: confirmation or rejection of a receipt by a named party.
- Signatures and Certified shared definitions: the DID and signature types a receipt uses.
- Guide: Funding and Learning, Trust and Recognition.