Skip to content

Fetching financial document PDFs via the AR-API

This guide explains how to retrieve issued financial documents for a booking and download their PDFs using the Accounts Receivable (AR) API. It applies to any integrator building a resident-facing portal or back-office integration.

The AR-API exposes every issued financial document. Documents belong to six families. Five have their own list query, and a generic documents query spans all of them.

Family Query Covers
Invoices invoices Invoices, corrective invoices (identified by the corrects field), charge notes, damages invoices, downpayment invoices
Credit notes creditNotes Credit notes, credit charge notes, downpayment credit notes, credit reversal notes
Receipts receipts Receipts, deposit receipts, downpayment receipts
Refund notes refundNotes Refund notes
Refund reversal notes documents (filter documentGenericType: { in: [REFUND_REVERSAL_NOTE] }) Refund reversal notes
Payment reversal notes reversalNotes Payment reversal notes

A corrective invoice is returned by the invoices query like any other invoice. Its corrects field identifies the document it corrects.

A refund reversal note has its own PDF, titled “Refund reversal note - RRN-…”. It shows which refund note it reverses and why, and the reversed refund note’s PDF shows “Reversed by: RRN-…”.

  • API credentials (a Bearer token) provisioned for your integration.
  • The workspaceId of the operator workspace.
  • The bookingId you want documents for (when scoping to a single booking).

Send GraphQL requests as HTTP POST with your Bearer token:

POST https://api.lavanda.app/graphql
Authorization: Bearer <API_TOKEN>
Content-Type: application/json

Query the relevant family connection. workspaceId is required. To return only the documents that should be visible to a resident, filter by bookingId and issued: true. Request the document id, any display fields you need, and the per-locale pdfs.

query Documents($filters: AccountingDocumentInvoiceFilters) {
accounting {
invoices(filters: $filters) {
edges {
node {
id
documentNumber
issuedAt
billingPeriod { from to }
amount { value currency }
pdfs {
locale
location { url expiresAt }
}
}
}
}
}
}
{
"filters": {
"workspaceId": { "eq": "<workspace-id>" },
"bookingId": { "eq": "<booking-id>" },
"issued": { "eq": true }
}
}

The same shape works for the other families by swapping the connection name and its filter input:

  • invoices uses AccountingDocumentInvoiceFilters
  • creditNotes uses AccountingDocumentCreditNoteFilters
  • receipts uses AccountingDocumentReceiptFilters
  • refundNotes uses AccountingDocumentRefundNoteFilters
  • reversalNotes uses AccountingDocumentReversalNoteFilters

To pull every family in one call, use the generic documents query and narrow with documentGenericType.

Common filter fields (all families):

Filter Purpose
workspaceId (required) The operator workspace
bookingId Scope to a single booking. Mutually exclusive with id
id Fetch specific documents by ID. Mutually exclusive with bookingId
issued true returns only issued documents (those with a legal document number and a retrievable PDF)
billingPeriodFrom / billingPeriodTo Narrow by billing period
family-specific subtype filter (e.g. invoiceType, receiptType) Narrow within a family

The pdfs field lists per-locale availability. Each entry is a locale for which a PDF is either ready (non-null location.url) or can be generated on demand (location.url is null). Locales that are entirely unavailable are omitted.

For the locale you want:

If location.url is present, download the PDF binary directly from that URL. It is a short-lived pre-signed link (expires in about 1 hour). Fetch it on demand and do not cache or store it.

Example listing response:

{
"data": {
"accounting": {
"invoices": {
"edges": [
{
"node": {
"id": "31c44172-6e0e-4d94-aea7-bad6de7a2fc9",
"pdfs": [
{
"locale": "pt",
"location": {
"url": "https://lvdam-invoicing.s3.eu-west-2.amazonaws.com/...",
"expiresAt": "2026-07-29T12:39:43.382215Z"
}
}
]
}
}
]
}
}
}
}

If location.url is null for the locale you need, generate it on demand with the generatePdf mutation, then download from the returned url:

mutation GeneratePdf($docId: ID!, $locale: String!) {
accounting {
documents {
generatePdf(id: $docId, locale: $locale) {
url
}
}
}
}
{ "docId": "31c44172-6e0e-4d94-aea7-bad6de7a2fc9", "locale": "pt" }

generatePdf works for a document in any family (it takes the document id).

Pass the locale that matches the resident’s language.

Market Available PDF locales
Portugal (PT) pt only. PT documents are the compliant Portuguese “Original” (ATCUD + QR); no other language is issued.
Non-PT markets en, es, fr
  • Only issued documents have a legal document number and a retrievable PDF. Always filter issued: true for resident-facing use.
  • Pre-signed URLs are short-lived (about 1 hour). Never persist them; regenerate on demand.
  • The list response can return the PDF URL inline, so in many cases you do not need a separate generatePdf call. Fall back to generatePdf only when the wanted locale’s url is null.