BankingCircle.Reporting (banking_circle v1.0.0)

Copy Markdown View Source

Asynchronous report generation: request a report, poll its status, then download it once ready — the three-step flow Banking Circle uses for reports too large to return synchronously (reconciliation, account activity, rejections, bank statements, camt.053, etc).

The flow

POST /api/v2/reports/requests/{report-type}    -> 202, Location header with request id
GET  /api/v2/reports/{request-id}/get-status    -> 202 Processing (Retry-After) | 302 Complete (Location: reportId)
GET  /api/v1/reports/download-report/{reportId} -> the report body

request_report/3 performs step 1 and returns just the request id (read from the Location response header, per the documented flow). poll_status/2 performs one status check. fetch_report/3 drives the whole flow for you, sleeping between polls per the server's Retry-After guidance (falling back to a fixed interval if absent) up to a caller-supplied timeout — this is almost always what you want unless you're building your own background job around the individual steps.

Report type identifiers

Accepts either a known atom (translated to the slug Banking Circle expects — see BankingCircle.Reporting.ReportType.known/0) or a raw string, so you're not blocked on us keeping an exhaustive list current: pass e.g. "held-payments-sanctions-screening" directly if we haven't added a matching atom yet.

Summary

Functions

Downloads a generated report by its report id (obtained from poll_status/2's {:complete, report_id}).

Drives the full request → poll → download flow, blocking (via Process.sleep/1 between polls) until the report is ready or timeout_ms elapses.

Checks the status of a previously-requested report.

Fetches the Standard Reconciliation Report synchronously (GET /api/v1/reports/reconciliation-report) — a direct alternative to the async request_report/3poll_status/2download/2 flow, specifically for reconciliation. Handles up to 50,000 payments per report inline; for larger date ranges or other report types, use the async flow (fetch_report/3 or the individual steps) instead.

Kicks off report generation and returns {:ok, request_id} — extracted from the response's Location header, per the documented flow (the request id is not in the response body). Pass the id to poll_status/2, or just use fetch_report/3 to handle the whole flow.

Types

client()

@type client() :: atom()

report_type()

@type report_type() :: atom() | String.t()

Functions

download(report_id, client \\ :default)

@spec download(String.t(), client()) ::
  {:ok, term()} | {:error, BankingCircle.Error.t()}

Downloads a generated report by its report id (obtained from poll_status/2's {:complete, report_id}).

fetch_report(report_type, attrs \\ %{}, opts \\ [])

@spec fetch_report(report_type(), map(), keyword()) ::
  {:ok, term()} | {:error, :timeout | BankingCircle.Error.t()}

Drives the full request → poll → download flow, blocking (via Process.sleep/1 between polls) until the report is ready or timeout_ms elapses.

For a web request handler, prefer request_report/3 plus a background job that calls poll_status/2 on a schedule instead of blocking a request process for a potentially multi-minute report generation — fetch_report/3 is meant for scripts, IEx sessions, and background workers that already expect to block.

poll_status(request_id, client \\ :default)

@spec poll_status(String.t(), client()) ::
  {:processing, non_neg_integer() | nil}
  | {:complete, String.t()}
  | {:error, BankingCircle.Error.t()}

Checks the status of a previously-requested report.

Returns {:processing, retry_after_ms}, {:complete, report_id}, or {:error, %BankingCircle.Error{}}.

reconciliation_report(filters \\ [], client \\ :default)

@spec reconciliation_report(
  keyword(),
  client()
) :: {:ok, term()} | {:error, BankingCircle.Error.t()}

Fetches the Standard Reconciliation Report synchronously (GET /api/v1/reports/reconciliation-report) — a direct alternative to the async request_report/3poll_status/2download/2 flow, specifically for reconciliation. Handles up to 50,000 payments per report inline; for larger date ranges or other report types, use the async flow (fetch_report/3 or the individual steps) instead.

request_report(report_type, attrs \\ %{}, client \\ :default)

@spec request_report(report_type(), map(), client()) ::
  {:ok, String.t()} | {:error, BankingCircle.Error.t()}

Kicks off report generation and returns {:ok, request_id} — extracted from the response's Location header, per the documented flow (the request id is not in the response body). Pass the id to poll_status/2, or just use fetch_report/3 to handle the whole flow.