Receipts
A receipt is the immutable record of a successful payment — issued automatically when a checkout session completes or an invoice is paid. Receipts have their own ID, their own URL, and their own template (controlled via the Templates namespace); they are decoupled from the underlying session or invoice so they survive even if the original is later voided. This page covers the plugipay.receipts namespace; for the underlying HTTP surface see API: Receipts, and for how receipts relate to other objects see Concepts → Receipt.
Namespace
plugipay.receipts — every method on this namespace:
plugipay.receipts.list(params?)
plugipay.receipts.get(id)
Receipts are created automatically by Plugipay on successful payment — you don't create them via the SDK. To re-issue / customize the rendered output, edit the receipt template and the change applies to subsequent receipts.
Methods
receipts.list
Signature. plugipay.receipts.list(params?): Promise<{ data: ReceiptSummary[]; cursor: string | null; hasMore: boolean }>
Cursor-paginated list of receipts. Filters: sourceType ('checkout_session' or 'invoice'), customerId, issuedAfter, issuedBefore (ISO-8601 strings), limit, cursor. See Pagination.
import { PlugipayClient } from '@forjio/plugipay-node';
const plugipay = new PlugipayClient({
keyId: process.env.PLUGIPAY_KEY_ID!,
secret: process.env.PLUGIPAY_SECRET!,
});
// All receipts for one customer:
const { data: customerReceipts } = await plugipay.receipts.list({
customerId: 'cus_01HX...',
limit: 50,
});
// All checkout receipts in the last 30 days:
const since = new Date(Date.now() - 30 * 86_400_000).toISOString();
const { data: recent } = await plugipay.receipts.list({
sourceType: 'checkout_session',
issuedAfter: since,
limit: 100,
});
The list returns ReceiptSummary objects — lightweight versions with the headline fields. To render or download the full document, fetch by ID.
receipts.get
Signature. plugipay.receipts.get(id): Promise<unknown>
Fetches the full receipt document — the typed return is unknown because the document shape depends on the underlying receipt template (which is workspace-configurable JSON). Cast or validate as needed.
type FullReceipt = ReceiptSummary & {
document: Record<string, unknown>;
hostedUrl: string;
pdfUrl: string;
};
const receipt = (await plugipay.receipts.get('rcp_01HX...')) as FullReceipt;
console.log(receipt.hostedUrl); // browser-friendly receipt page
console.log(receipt.pdfUrl); // direct PDF link
Types
interface ReceiptSummary {
id: string; // 'rcp_...'
number: string; // human-readable, e.g. 'RCP-2026-00118'
sourceType: 'checkout_session' | 'invoice';
sourceId: string; // 'cs_...' or 'inv_...'
customerId: string | null;
amount: number; // minor units
currency: string;
method: string | null; // 'qris' / 'card' / etc.
adapter: string | null; // 'xendit' / 'midtrans' / ...
issuedAt: string; // ISO-8601
emailedAt: string | null;
emailedTo: string | null;
}
For the full document shape (which depends on the active receipt template), see API: Receipts and API: Templates.
Common patterns
Show a customer their receipt history
The customer-portal "Receipts" tab is just a filtered list:
async function customerReceipts(customerId: string) {
const results: ReceiptSummary[] = [];
let cursor: string | undefined;
while (true) {
const page = await plugipay.receipts.list({
customerId,
limit: 50,
cursor,
});
results.push(...page.data);
if (!page.hasMore) break;
cursor = page.cursor!;
}
return results;
}
If you'd rather not build the UI yourself, mint a portal session and let the customer view receipts in the Plugipay-hosted portal.
Download a receipt PDF
async function downloadReceiptPdf(receiptId: string): Promise<Buffer> {
const r = (await plugipay.receipts.get(receiptId)) as { pdfUrl: string };
const res = await fetch(r.pdfUrl);
return Buffer.from(await res.arrayBuffer());
}
const pdf = await downloadReceiptPdf('rcp_01HX...');
await fs.writeFile('receipt.pdf', pdf);
Reconcile receipts to ledger transactions
Every receipt corresponds to ledger entries posted at the moment of completion. To verify a receipt is accounted-for:
async function ledgerForReceipt(receiptId: string) {
const receipt = await plugipay.receipts.get(receiptId) as ReceiptSummary & { document: any };
// Receipts are derived from their source — query the ledger by the source ID:
return plugipay.ledger.list({
sourceType: receipt.sourceType,
sourceId: receipt.sourceId,
});
}
Find receipts sent to a specific address
The emailedTo field captures the address Plugipay sent each receipt to (it may differ from the customer's primary email if you overrode it). For "did we email finance@ this month's receipts?" audits:
async function receiptsEmailedTo(addr: string, from: string, to: string) {
const all: ReceiptSummary[] = [];
let cursor: string | undefined;
while (true) {
const page = await plugipay.receipts.list({
issuedAfter: from,
issuedBefore: to,
limit: 100,
cursor,
});
all.push(...page.data.filter((r) => r.emailedTo === addr));
if (!page.hasMore) break;
cursor = page.cursor!;
}
return all;
}
Build a monthly receipt export
For accounting hand-off:
async function* receiptsForMonth(year: number, month: number) {
const start = new Date(Date.UTC(year, month - 1, 1)).toISOString();
const end = new Date(Date.UTC(year, month, 1)).toISOString();
let cursor: string | undefined;
while (true) {
const page = await plugipay.receipts.list({
issuedAfter: start,
issuedBefore: end,
limit: 100,
cursor,
});
for (const r of page.data) yield r;
if (!page.hasMore) break;
cursor = page.cursor!;
}
}
const rows: string[] = ['number,customer,amount,currency,adapter,issuedAt'];
for await (const r of receiptsForMonth(2026, 11)) {
rows.push([r.number, r.customerId ?? '', r.amount, r.currency, r.adapter ?? '', r.issuedAt].join(','));
}
await fs.writeFile('receipts-2026-11.csv', rows.join('\n'));
Errors
| Code | Status | Cause |
|---|---|---|
validation_error |
400 | Bad date format in issuedAfter / issuedBefore, unknown sourceType. |
not_found |
404 | Receipt ID doesn't exist or is in another workspace. |
forbidden |
403 | Key lacks the plugipay:receipt:read scope. |
Next
- Checkout sessions — one source of receipts.
- Invoices — the other source.
- Portal sessions — hand off receipt browsing to the customer.
- API: Receipts — HTTP reference.