Title: API to Extract Transactions from PDF Bank Statements Canonical URL: https://bankstatement.ai/blog/extract-transactions-pdf-bank-statements-api Updated: 2026-07-20 Category: core-developer-intent # API to Extract Transactions from PDF Bank Statements ## TL;DR - Treat extraction as an asynchronous pipeline: preflight, submit, poll, retrieve, review, and store. - Authenticate from a trusted server with a bearer token. Never expose a real token in client code, logs, or examples. - Use normalized JSON for application logic. Request CSV or XLSX for spreadsheet handoffs. - Poll with a client-defined stopping limit because customer-facing webhooks are unavailable. - Supported inputs are PDF, CSV, and XLSX. Each statement is limited to 25 MB and 100 pages. - Retrieve authorized results and exports within seven days. API-call metadata has a separate ninety-day retention period. A developer can upload a valid scanned statement and still produce an unsafe accounting import. Processing may remain unfinished, extraction issues may require review, or the client may map an amount incorrectly. A reliable API to extract transactions from PDF bank statements therefore needs a bounded, reviewable pipeline, not a single upload call. ## Table of Contents - [Key Takeaways](#key-takeaways) - [Map the Request Sequence](#map-the-request-sequence) - [Protect the Token and Preflight the File](#protect-the-token-and-preflight-the-file) - [Submit One PDF as a Multipart Job](#submit-one-pdf-as-a-multipart-job) - [Poll Within a Client-Owned Bound](#poll-within-a-client-owned-bound) - [Retrieve JSON and Apply a Verification Gate](#retrieve-json-and-apply-a-verification-gate) - [Choose JSON, CSV, or XLSX](#choose-json-csv-or-xlsx) - [Prepare the Integration for Production](#prepare-the-integration-for-production) - [FAQ](#faq) ## Key Takeaways - Preflight every candidate statement before creating a processing job. - Keep bearer tokens in server-side secret storage and redact identifiers from logs. - Treat successful processing and acceptable data quality as separate decisions. - Review the overall verification summary before importing normalized transactions. - Choose JSON for software workflows and CSV or XLSX for spreadsheet users. - Test varied synthetic or authorized statements because no public accuracy benchmark or processing-time SLA is available. ## Map the Request Sequence A single-statement integration uses five endpoints in order: 1. Send the candidate file to `POST /api/v1/uploads/preflight`. 2. Submit one accepted statement to `POST /api/v1/jobs` with `multipart/form-data`. 3. Poll `GET /api/v1/jobs/:id` while processing continues. 4. Retrieve normalized transaction JSON from `GET /api/v1/results/:id` after successful completion. 5. Optionally retrieve CSV or XLSX from `GET /api/v1/results/:id/exports/:kind`. Each stage has a different responsibility. Preflight decides whether the candidate can proceed. Submission creates asynchronous work. Polling determines when that work reaches a terminal outcome. Result retrieval obtains structured data, and verification determines whether the application may use it. ![Five-step API sequence from file preflight through job submission and polling to JSON results and optional exports.](https://files.trafficwins.com/generated-images/0371334e-670e-4ffe-a66a-c61eca5d47f4/b5fd67a3-066f-5b56-9dd6-077d556a91fb/2aa2f542-06f1-4b1b-8fce-ee9de0fa613a/697fb332-7202-4920-a45e-63e670af2613/inline-1.png) Use one synthetic PDF throughout the first integration test. For example, create a fictional two-page checking statement with an invented account suffix and these clearly labeled test transactions: | Date | Description | Amount | |---|---|---:| | 2026-06-03 | SAMPLE PAYROLL CREDIT | 2400.00 | | 2026-06-05 | SAMPLE ELECTRIC PAYMENT | -68.14 | | 2026-06-07 | SAMPLE MONTHLY FEE | -12.50 | This table is a test fixture, not an API response or customer result. Its purpose is to give the team known values to compare with the returned transaction data. Do not use private customer statements as development fixtures. ## Protect the Token and Preflight the File Bearer authentication belongs in a trusted server environment. Store the API token in a managed secret store or protected environment variable. Restrict access to the service making requests, rotate the token when needed, and prevent it from entering source control, browser code, logs, screenshots, or support messages. The authorization header follows this pattern: ```http Authorization: Bearer YOUR_REDACTED_TOKEN ``` Before submission, call `POST /api/v1/uploads/preflight`. The client should treat preflight as an accept-or-reject boundary. If the file is rejected, show the operator a useful error and do not create a job for the same unchanged file. Supported inputs are PDF, CSV, and XLSX. PDF processing includes OCR for scanned statements. Standalone JPG, PNG, TIFF, and HEIC uploads are not supported. The maximum is 25 MB and 100 pages per statement. The website's published product summary also identifies PDF OCR, CSV, and XLSX uploads, along with spreadsheet outputs ([bankstatement.ai product summary](https://bankstatement.ai/llm.txt)). Enforce the known format, size, and page rules in the client before preflight so obvious failures do not consume unnecessary requests. Preflight request fields, returned properties, and rejection categories must match the current API reference used by the implementation team. Keep their handling in a small adapter rather than spreading response assumptions across the application. That makes a documented API change easier to isolate. ## Submit One PDF as a Multipart Job After preflight accepts the synthetic statement, submit it to `POST /api/v1/jobs` using `multipart/form-data`. The request needs the bearer authorization header and the documented multipart file part. A language-neutral request outline is: ```http POST /api/v1/jobs HTTP/1.1 Authorization: Bearer YOUR_REDACTED_TOKEN Content-Type: multipart/form-data; boundary=BOUNDARY --BOUNDARY Content-Disposition: form-data; name="FILE_PART_FROM_API_REFERENCE"; filename="synthetic-statement.pdf" Content-Type: application/pdf [BINARY PDF CONTENT] --BOUNDARY-- ``` `FILE_PART_FROM_API_REFERENCE` is a configuration label, not a proposed field name. Set it from the current API reference before running the request. The same rule applies to the service base URL and any additional documented parts. Handle the response as job creation, not transaction delivery. Save the documented job identifier in an internal record that also contains your own import identifier. Redact API identifiers from public logs and user-visible error reports. An accepted request does not prove that extraction has completed. Persist enough local state to resume status checks after a worker restart, and prevent a duplicate operator action from creating an unintended second import. ## Poll Within a Client-Owned Bound Query `GET /api/v1/jobs/:id` for asynchronous status. Customer-facing webhooks are unavailable, so the client owns the polling schedule, retry policy, and stopping condition. Use a bounded control flow: ```text set a maximum number of attempts or an elapsed-time deadline while the client limit remains: request GET /api/v1/jobs/ if the documented state means work continues: wait according to the client policy continue if the documented state means success: save the documented result identifier stop polling if the documented state means failure: record a sanitized error route the import for handling stop polling otherwise: stop polling raise a compatibility alert if the client limit expires: mark the local import as awaiting investigation ``` Map the actual state values from the current API reference. Do not infer them from generic labels such as `processing`, `complete`, or `failed`. The stopping bound prevents a stuck or unfamiliar job from consuming workers forever. An unknown state should also stop automation. Treating it as continued processing could conceal an API change, while treating it as success could admit incomplete data. Set request intervals and retry behavior after checking the current documentation for HTTP errors, retry instructions, and any published rate limits. No public processing-time SLA is available, so a client deadline is an operational safeguard, not an estimate of how long extraction should take. ## Retrieve JSON and Apply a Verification Gate After a documented successful outcome, retrieve normalized transaction JSON through `GET /api/v1/results/:id`. Preserve the raw authorized response separately from the accepted accounting record so a validation failure cannot create a partial import. ![JSON results pass an overall verification gate and transaction validation before staging; issues route to review.](https://files.trafficwins.com/generated-images/0371334e-670e-4ffe-a66a-c61eca5d47f4/b5fd67a3-066f-5b56-9dd6-077d556a91fb/2aa2f542-06f1-4b1b-8fce-ee9de0fa613a/697fb332-7202-4920-a45e-63e670af2613/inline-2.png) The result includes an overall conversion verification summary with confidence and issues. This summary applies to the conversion as a whole. It is not a field-level confidence score for every date, description, or amount. Use two gates before posting transactions: 1. Inspect the overall verification summary. Route results with relevant issues to an exception queue or human review. 2. Validate each transaction against the application's own import rules, using only fields and types defined in the current result schema. A schema-independent handling pattern is: ```text result = request GET /api/v1/results/ summary = obtain the documented overall verification summary if summary requires review under the application policy: preserve the authorized result create an exception task stop automatic posting transactions = obtain the documented transaction collection for each transaction: validate required values and types map documented date, description, and amount data reject or review invalid records commit only after the complete statement passes ``` For the synthetic fixture, compare the returned values with the three known transactions. Check date representation, description normalization, amount signs, null behavior, and duplicate handling against the documented schema. Never write a production mapper from an assumed JSON shape. A useful application policy might allow a clean synthetic result into a staging table while directing any reported issue to a bookkeeper. The staging boundary provides a place to inspect mapping behavior without posting entries to a ledger. ## Choose JSON, CSV, or XLSX Normalized JSON is the primary output when software is the next consumer. It supports validation, database mapping, exception routing, and transaction-import logic without an extra spreadsheet parsing step. Use `GET /api/v1/results/:id/exports/:kind` when the next consumer needs a file. CSV suits tabular import tools and simple data exchanges. XLSX suits operators who need to inspect the transactions in a workbook. | Next consumer | Preferred output | Decision reason | |---|---|---| | Application service | JSON | Supports typed validation and internal mapping | | Bookkeeper's import tool | CSV | Provides a portable tabular handoff | | Workbook-based review | XLSX | Preserves a spreadsheet-oriented file | Set `:kind` to the documented value for CSV or XLSX and validate the returned content type before saving the file. This endpoint does not imply QBO, OFX, direct QuickBooks or Xero synchronization, or another accounting integration. If a receiving system requires a different format, your application must create and test that transformation. ## Prepare the Integration for Production Results and generated exports are retained for seven days. Copy authorized outputs into your approved system promptly, then apply your own access controls and deletion policy. Do not depend on the extraction service as permanent hosted storage. API-call metadata has a separate ninety-day retention period. Record these lifecycles separately in security reviews and customer explanations because output availability and call metadata are different data classes. Before approving production use, confirm that: - Client-side checks reject unsupported formats and known size or page-limit violations. - Tokens cannot enter source control, browser code, ordinary logs, or error reports. - Preflight fields, multipart parts, identifiers, and response properties match the current API reference. - Polling has a firm bound and explicit handling for failure, timeouts, and unknown states. - Documented HTTP errors, retry instructions, and rate limits have tests. - Successful processing leads to verification review before import. - Transaction mappings use documented names, types, signs, date formats, and null behavior. - Authorized results and exports are copied before the seven-day window ends. - The team can operate without customer-facing webhooks, image uploads, or direct accounting exports. No public accuracy benchmark or processing-time SLA is available. Test the workflow with varied synthetic or properly authorized samples that reflect the layouts and scan quality the product will encounter. Record observed exceptions and decide which ones block automatic posting, require review, or reject an import. The workflow is a practical fit when the product can accept polling, the supported formats, an overall verification gate, and short output retention. It needs caution when the design depends on event callbacks, direct accounting synchronization, permanent hosted results, or a guaranteed completion time. ## FAQ ### Can scanned PDF bank statements be processed? Yes. PDF processing supports OCR for scanned statements. Scan quality and bank layouts vary, so test representative synthetic or authorized files before deciding which results can proceed automatically. ### Can I upload JPG, PNG, TIFF, or HEIC files? No. Supported inputs are PDF, CSV, and XLSX. If an authorized workflow converts an image to PDF, verify legibility, page order, orientation, and access controls before submission. ### Are webhooks available for completion events? Customer-facing webhooks are unavailable. The integration must poll `GET /api/v1/jobs/:id` and stop when it reaches a documented terminal outcome, an unknown state, or its own waiting limit. ### What should happen when the polling limit expires? Do not assume failure or create another job automatically. Mark the local import for investigation, retain its job association, and allow an authorized operator or recovery process to check the documented status safely. ### How long are results and exports available? Results and exports are retained for seven days. Copy approved outputs into your authorized system before that period ends. API-call metadata has a separate ninety-day retention period. ### Should an accounting product use JSON, CSV, or XLSX? Use normalized JSON for validation and application logic. Choose CSV for a tabular import handoff or XLSX for workbook-based review. Transformations into other accounting formats remain the integrating application's responsibility. ### What is the safest first trial? Create an account, get an API token, and process a synthetic statement. Run it through preflight, one multipart submission, bounded polling, verification review, JSON validation, and timely storage before introducing authorized production data.