Skip to content

Fetch reports and files through the API

Reports and files are not pushed to an SFTP server. You fetch them with the API, with a token that has the right for each call. This page shows which call gets which file, how to scope a call to one client, and how to generate the client reports on demand. For what each report contains and who receives it, see Reports and files Quiddly sends and Client Portal, Reports.

You want Call Right
Reports Quiddly sent to a client (settlement notes, activity, payment and booked invoice reports, scheduled reports) POST /reports/distribution-archive/search, then GET /reports/distribution-archive/<id>/file ReadReportArchive
Generated client reports by type and status POST /reports/transaction-reports/search, then GET /storage/<fileName> SearchTransactionReports
Payout files POST /payout-batches/search, then GET /storage/<fileName> SearchPayoutBatches, ReadPayoutFile
Payout journal as PDF POST /reports/query-reports/QR.200021/query?format=pdf QueryReport
Query reports (financed invoices, payments, ledgers, …) POST /reports/query-reports/<id>/query QueryReport, ReadQueryReport
BGMAX and KTL files PUT /bookkeeping-files/generate, POST /bookkeeping-files/search, GET /storage/<fileName> GenerateBookkeepingFile, SearchBookkeepingFiles

Which token, and how to scope it to a client

Section titled “Which token, and how to scope it to a client”

Use a service account at admin level (a SYSTEM role account, see Authentication). One token reaches every client, and you scope a call to a client yourself:

  • Archive and search calls take a clientId in the body. The exception is POST /payout-batches/search: a payout batch does not belong to one client, and a clientId in that body is refused with a 400.
  • Query reports take a clientId filter in the payload, for the reports that define one.

The alternative is a client-specific token, which a client creates in the Client Portal under Configure, Integrations, Create new integration. The token is shown once, when the integration is created. With a client token the client is taken from the token: a clientId you send in a query report filter is replaced by the token’s own client.

Use the admin-level account when you serve several clients, and a client token when an integration should only ever see one client.

The distribution archive holds what the system has distributed to a client, and the files uploaded into it. It is the same list the client sees under Distribution Archive in the Client Portal.

Terminal window
curl -X POST "https://$HOST/reports/distribution-archive/search?limit=50&order=desc" \
-H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
-d '{
"clientId": "C.100100",
"reportType": ["FACTORING_SETTLEMENT_NOTE", "ACTIVITY_REPORT_DAILY"],
"fromDate": "2026-09-01",
"toDate": "2026-09-30"
}'

Every filter is optional. reportType and currency are lists, and the dates are YYYY-MM-DD. Rows come newest first (orderBy can only be generatedDate), with the total in the X-Total-Count header.

reportType Report
FACTORING_SETTLEMENT_NOTE, INVOICE_SETTLEMENT_NOTE, BUSINESS_LOAN_SETTLEMENT_NOTE, OVERDRAWN_SETTLEMENT_NOTE The settlement notes
ACTIVITY_REPORT, ACTIVITY_REPORT_DAILY The monthly and daily activity reports, in any format
PAYMENT_REPORT, BOOKED_INVOICE_REPORT The payment transaction report and the booked invoice report
QUERY_REPORT A scheduled query report
UPLOADED_REPORT, OTHER Files uploaded into the archive, and anything else

Download one row with its id. Send the client again with an admin-level token:

Terminal window
curl "https://$HOST/reports/distribution-archive/$ID/file?clientId=C.100100" \
-H "Authorization: Bearer $JWT" -o report

The file comes in the format it was made in, which the row shows in format.

Generated client reports by type and status

Section titled “Generated client reports by type and status”

To find reports by type, client and status, search the transaction reports. A report is GENERATED, then AUTHORIZED, then EXPORTED.

Terminal window
curl -X POST "https://$HOST/reports/transaction-reports/search" \
-H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
-d '{ "clientId": "C.100100", "type": "ACTIVITY_REPORT_DAILY_XML", "status": "EXPORTED" }'

Each report carries its documents, with the type and fileName of each file. Download a file by its name from the storage API:

Terminal window
curl "https://$HOST/storage/$FILE_NAME" -H "Authorization: Bearer $JWT" -o report.xml

Reading a single report by id needs ReadTransactionReport. The type is one of:

type Report
FACTORING_SETTLEMENT_NOTE, INVOICE_SETTLEMENT_NOTE, BUSINESS_LOAN_SETTLEMENT_NOTE, OVERDRAWN_SETTLEMENT_NOTE The settlement notes. Their Excel and XML files are listed among the documents of the same report
FACTORING_SETTLEMENT_NOTE_XML, INVOICE_SETTLEMENT_NOTE_XML XML settlement notes that are reports of their own
PAYMENT_TRANSACTION_CLIENT_REPORT, PAYMENT_TRANSACTION_CLIENT_REPORT_BGMAX The payment transaction report, as PDF and as BGMAX
BOOKED_INVOICE_REPORT The booked invoice report
ACTIVITY_REPORT, ACTIVITY_REPORT_XLSX, ACTIVITY_REPORT_XML The monthly activity report, one report per format
ACTIVITY_REPORT_DAILY, ACTIVITY_REPORT_DAILY_XLSX, ACTIVITY_REPORT_DAILY_XML The daily activity report, one report per format

List the payout batches, then download the file of each batch. Exported batches have status EXPORTED.

Terminal window
curl -X POST "https://$HOST/payout-batches/search" \
-H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
-d '{ "status": "EXPORTED" }'

Each batch has a documents list with fileName for each payout file. Download it from GET /storage/<fileName>, which needs ReadPayoutFile for a payout file.

The payout journal for one batch is a query report with the id QR.200021, which requires a payoutBatchId filter. This is how you get it as a PDF:

Terminal window
curl -X POST "https://$HOST/reports/query-reports/QR.200021/query?format=pdf" \
-H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
-d '{
"select": [
{ "field": "payoutDate" }, { "field": "receiver" }, { "field": "toChannel" },
{ "field": "currency" }, { "field": "amount" }
],
"filter": [{ "field": "payoutBatchId", "operator": "EQ", "value": "POB.1001" }],
"limit": 1000
}' -o payout-journal.pdf

Always send a limit. Without one, the report’s own default applies, and the payout journal defaults to 10 rows, so the PDF would hold only the 10 largest payouts of the batch. Use a limit at least as large as the number of payouts in the batch.

A query report is a saved report definition that you run with your own columns, filters and order. Read the definition first, to see which fields it allows:

Terminal window
curl "https://$HOST/reports/query-reports/$REPORT_ID" -H "Authorization: Bearer $JWT"

This needs ReadQueryReport, and GET /reports/query-reports lists the reports you can run. The standard reports have the same ids in every environment, and a report built for one environment has its own, so confirm an id against the list. Then run the report, with QueryReport. This example runs the standard Payments report, QR.200001:

Terminal window
curl -X POST "https://$HOST/reports/query-reports/QR.200001/query?format=json" \
-H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
-d '{
"select": [
{ "field": "invoiceNumber" }, { "field": "transactionDate" },
{ "field": "amountCapital" }, { "field": "invoiceCurrency" }
],
"filter": [
{ "field": "clientId", "operator": "EQ", "value": "C.100100" },
{ "field": "eventType", "operator": "EQ", "value": "PAYMENT" }
],
"order": [{ "field": "transactionDate", "order": "DESC" }],
"limit": 100,
"page": 1
}'
  • format is json (default), csv, pdf or xlsx.
  • select is required and every field must be one the definition lists.
  • A filter takes EQ, NE, GT, LT, GE, LE or IN, but only the operators the definition allows for that field. A definition can also require a filter.
  • For IN, send the values as one string separated by commas. Spaces are ignored.
  • Page with limit and page. page is the page number, starting at 1: the second batch of 100 rows is "limit": 100, "page": 2. Without a limit, the report’s own default limit applies, if it has one. For a large result, fetch it batch by batch rather than in one call.

BGMAX files (Swedish clients) and KTL files (Finnish clients) are bookkeeping files. They are generated first, then listed, downloaded and marked exported. There is no shorter route, so build the four steps into your integration and monitor the result.

  1. Generate with PUT /bookkeeping-files/generate (GenerateBookkeepingFile). For BGMAX and KTL at least one filterCode is required.

    Terminal window
    curl -X PUT "https://$HOST/bookkeeping-files/generate" \
    -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
    -d '{
    "clientId": "C.100100", "type": "BGMAX", "content": ["PAYMENTS"],
    "filterCode": ["ALL"], "fromDate": "2026-09-01", "toDate": "2026-09-30"
    }'

    One file is created per booking day and currency in the period. Generation runs in the background, so list the files after a few seconds.

  2. List the files with POST /bookkeeping-files/search (SearchBookkeepingFiles), filtering on clientId, type and status (CREATED or EXPORTED).

  3. Download each file from GET /storage/<documentFileName>.

  4. Mark it exported with PUT /bookkeeping-files/<id>/export (ExportBookkeepingFile). This only works while the file is CREATED.

See Export internal bookkeeping for the record fields and for SIE files.

The daily routine generates, authorizes and exports the client reports. You can run the same three steps through the API. The calls work on all clients at once, and each needs its own right.

  1. Generate with PUT /reports/transaction-reports/generate (GenerateTransactionReports):

    Terminal window
    curl -X PUT "https://$HOST/reports/transaction-reports/generate" \
    -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
    -d '{ "transactionDate": "2026-10-01", "override": false }'

    instanceProviderId limits the run to one instance provider, and override makes the activity reports for the date again if they already exist. The call is refused with 400 There can only be one collection of transaction reports in progress at a time while earlier transaction reports are still waiting to be authorized or exported (status GENERATED or AUTHORIZED). Payout batches do not block it, but generate the reports after the day’s payouts have been exported, so the settlement notes include them.

  2. Authorize with PUT /reports/transaction-reports/authorize (AuthorizeTransactionReports), with the same transactionDate.

  3. Export with PUT /reports/transaction-reports/export (ExportTransactionReports), with the same transactionDate. Exporting is what sends the reports to the clients.

The daily activity report has its own scheduled job each morning, so the run above may skip it. If you need it at another time, contact Quiddly support.