Bank Statement
The Bank Statement API lets you request and download a monthly bank statement (PDF) for a Virtual Bank Account (VBA). Statements are generated asynchronously: you request a statement for a given month, poll for its status, and download the PDF once it is ready. You can also subscribe to a webhook to be notified automatically when a statement has been generated.
A typical use case is sharing a VBA bank statement with a third party (for example, a marketplace such as Amazon) to verify your bank account.
Authorization
OAuth2 token is required in the Authorization header.
HeadersThree headers are required to use this endpoint.
Required Headers
<th style={{ textAlign: "left" }}> Type </th> <th style={{ textAlign: "left" }}> Required </th> <th style={{ textAlign: "left" }}> Description </th> </tr> </thead> <tbody> <tr> <td style={{ textAlign: "left" }}> `Authorization` </td> <td style={{ textAlign: "left" }}> `string` </td> <td style={{ textAlign: "left" }}> Yes </td> <td style={{ textAlign: "left" }}> Bearer token (OAuth 2.0) This header holds the bearer token required to use Veem's public API, and **belongs to the owner account**. Failure to use a valid bearer token will result in a 404 (Not Found) status code in the response. An example of a valid header value is as follows: `Bearer c047594b-082c-4da1-be89-08fe3770f4b3` See [Get Access Token section](https://developer.veem.com/docs/oauth#1---get-access-token) to generate your Bearer token </td> </tr> <tr> <td style={{ textAlign: "left" }}> `X-Request-Id` </td> <td style={{ textAlign: "left" }}> `string` </td> <td style={{ textAlign: "left" }}> Yes </td> <td style={{ textAlign: "left" }}> This is a unique string that identifies the current API request, and should follow the UUID format. Reusing this header without changing the value will result in a 409 (Conflict) status code in the response. An example X-request-id is as follows:\ `48855846-628d-4177-b071-80332a116f0a` </td> </tr> <tr> <td style={{ textAlign: "left" }}> `Content-Type` </td> <td style={{ textAlign: "left" }}> `string` </td> <td style={{ textAlign: "left" }}> Yes </td> <td style={{ textAlign: "left" }}> The content type of the request. Must be `application/json` </td> </tr> </tbody>
Bank Statement Endpoints
Use the following base URL to access the endpoints in the sandbox environment.
https://sandbox-api.veem.com/veem/
| Action | Endpoint |
|---|---|
| Request a bank statement | POST /v1.2/virtual-bank-account/statements |
| Get a bank statement | GET /v1.2/virtual-bank-account/statements/{statementRequestId} |
Request a Bank Statement
Requests the generation of a bank statement for a Virtual Bank Account for a given year and month. Generation is asynchronous, so the response is returned immediately with status set to IN_PROGRESS and no download URL yet. Poll the Get a Bank Statement endpoint (or subscribe to the Bank Statement Webhook) to know when the PDF is ready.
POST /v1.2/virtual-bank-account/statements
Partner Notes:
- A partner account can be configured to make this API request on behalf of their customers. This requires internal configuration for the partner account by Veem. Once the internal configuration is enabled, the API request can be made using the partner account bearer token.
onBehalfAccountIdis an optional parameter, this needs to be included in the request body in case of a partner making an API request on behalf of their customer. This is the customer Veem account ID.
Request Payload
{
"fundingMethodId": 55073,
"year": 2026,
"month": 4,
"onBehalfAccountId": 123456
}
Request Parameters
| Parameter | Mandatory? | Format/Values | Size/Type |
|---|---|---|---|
fundingMethodId | Yes | The funding method ID of the Virtual Bank Account the statement is requested for. Use List Funding Methods to retrieve it. | Long |
year | Yes | The statement year. Must be between 2000 and 2999. | Integer |
month | Yes | The statement month. Must be between 1 (January) and 12 (December). | Integer |
onBehalfAccountId | No | The customer Veem account ID. Include only when a partner makes the request on behalf of their customer. | Long |
Response Payload
Once a valid request has been sent, a response payload of this format should be expected:
{
"statementRequestId": 4821,
"resourceType": "VBA",
"fundingMethodId": 55073,
"year": 2026,
"month": 4,
"status": "IN_PROGRESS",
"createdAt": 1746057600000,
"updatedAt": 1746057600000
}
Response Parameters
| Parameter | Type | Description |
|---|---|---|
statementRequestId | integer | Unique identifier of the statement request. Use it to poll status and download the statement. |
resourceType | string | The resource the statement was requested for. Currently always VBA. |
fundingMethodId | integer | Funding method ID of the Virtual Bank Account the statement was requested for. |
year | integer | The statement year. |
month | integer | The statement month (1–12). |
status | string | Current status of the statement request. See Statement Statuses. |
createdAt | integer | Timestamp when the statement request was created, in Java epoch format (milliseconds). |
updatedAt | integer | Timestamp when the statement request was last updated, in Java epoch format (milliseconds). |
downloadUrl | string | Pre-signed URL to download the statement PDF. Only present when status is COMPLETED. |
expiresAt | integer | Timestamp when downloadUrl expires, in Java epoch format (milliseconds). Only present when status is COMPLETED. |
generatedAt | integer | Timestamp when the statement PDF was generated, in Java epoch format (milliseconds). Present once generation has finished. |
failureReason | string | Description of the failure. Only present when status is FAILED. |
IdempotencyRequesting a statement for the same Virtual Bank Account and the same
year/monthreturns the existingstatementRequestIdinstead of creating a duplicate. A statement that previously ended inFAILEDis automatically reset toIN_PROGRESSand re-generated.
Get a Bank Statement
Retrieves the current status of a statement request. When the statement is ready (status = COMPLETED), the response also includes a downloadUrl that you can use to download the statement PDF.
// Example request: GET /v1.2/virtual-bank-account/statements/4821
GET /v1.2/virtual-bank-account/statements/{statementRequestId}
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
statementRequestId | integer | Yes | The ID returned by the Request a Bank Statement endpoint. |
Query String Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
onBehalfAccountId | integer | No | The customer Veem account ID. Include only when a partner makes the request on behalf of their customer. |
Response Payload (Completed)
When the statement is ready, the response includes the downloadUrl and its expiration:
{
"statementRequestId": 4821,
"resourceType": "VBA",
"fundingMethodId": 55073,
"year": 2026,
"month": 4,
"status": "COMPLETED",
"downloadUrl": "https://veem-generated-docs.s3.amazonaws.com/statements/4821.pdf?X-Amz-Signature=...",
"expiresAt": 1746057900000,
"createdAt": 1746057600000,
"updatedAt": 1746057650000,
"generatedAt": 1746057650000
}
Response Payload (In Progress)
While the statement is still being generated, no download URL is returned:
{
"statementRequestId": 4821,
"resourceType": "VBA",
"fundingMethodId": 55073,
"year": 2026,
"month": 4,
"status": "IN_PROGRESS",
"createdAt": 1746057600000,
"updatedAt": 1746057600000
}
Response Payload (Empty)
When there are no transactions for the requested period, the request completes with status EMPTY and no PDF is produced:
{
"statementRequestId": 4821,
"resourceType": "VBA",
"fundingMethodId": 55073,
"year": 2026,
"month": 4,
"status": "EMPTY",
"createdAt": 1746057600000,
"updatedAt": 1746057650000,
"generatedAt": 1746057650000
}
Response Payload (Failed)
When generation fails, the request carries status FAILED and a failureReason. Re-submitting the same request (same VBA + year/month) retries the generation:
{
"statementRequestId": 4821,
"resourceType": "VBA",
"fundingMethodId": 55073,
"year": 2026,
"month": 4,
"status": "FAILED",
"failureReason": "Unable to generate statement document",
"createdAt": 1746057600000,
"updatedAt": 1746057650000
}
Download URL expirationThe
downloadUrlis a short-lived pre-signed URL (valid for approximately 5 minutes). Download the PDF beforeexpiresAt. If the link has expired, simply call this endpoint again to obtain a freshdownloadUrl.
Statement Statuses
| Status | Description |
|---|---|
IN_PROGRESS | The statement request has been accepted and the PDF is being generated. No download URL yet. |
COMPLETED | The statement PDF has been generated and is ready to download via downloadUrl. |
EMPTY | The request completed successfully, but there were no transactions for the period, so no PDF was generated. |
FAILED | Statement generation failed. See failureReason. Re-submit the request to retry. |
Error Responses
| HTTP Status | Code | Description |
|---|---|---|
400 | 302 | Invalid payload. Returned when a mandatory field (fundingMethodId, year, month) is missing or out of range. The message field lists the offending fields. |
400 | 20009148 | INVALID_STATEMENT_PERIOD — the requested period is in the future, is the current month, or is before the Virtual Bank Account creation date (UTC). Statements are only available for fully elapsed months. |
401 | — | Unauthorized. Full authentication is required to access this resource. |
404 | — | Invalid bearer token. |
404 | 20009147 | STATEMENT_REQUEST_NOT_FOUND — no statement request matches the supplied statementRequestId for the account. |
404 | 20009149 | STATEMENT_RESOURCE_NOT_FOUND — the Virtual Bank Account referenced by fundingMethodId was not found for the account. |
409 | — | Conflict. Returned when the X-Request-Id header value is reused. |
Example validation error (400):
{
"error": "Invalid payload",
"message": "year: must not be null; month: must not be null",
"code": 302
}
Example period error (400):
{
"message": "Invalid statement period: year=2026, month=6. Period must not be in the future and must be after the resource creation date.",
"code": 20009148
}
Example not-found error (404):
{
"message": "Statement request 4821 not found for account 943802",
"code": 20009147
}
Bank Statement Webhook
Instead of polling, you can subscribe to the BANK_STATEMENT_CREATED webhook to be notified automatically when a statement has finished generating (for both COMPLETED and EMPTY outcomes).
For creating a webhook to be notified when a bank statement event occurs, use the following endpoint.
POST /v1.2/webhooks
| Event | Description |
|---|---|
| BANK_STATEMENT_CREATED | Notifies you when a bank statement has been generated for a Virtual Bank Account. |
To subscribe to this webhook notification, use the following request:
{
"callbackURL": "https://webhook-test.com/958892dcc2b3076fffd136adb127ac55",
"event": "BANK_STATEMENT_CREATED"
}
{
"id": 104,
"event": "BANK_STATEMENT_CREATED",
"callbackUrl": "https://webhook-test.com/958892dcc2b3076fffd136adb127ac55",
"status": "Active"
}
Once subscribed, when a bank statement is generated you will get a notification in the following format. The event information is contained in the data field in a stringified JSON format.
{
"type": "BANK_STATEMENT_CREATED",
"data": "{\"statementRequestId\":4821,\"accountId\":943802,\"resourceType\":\"VBA\",\"resourceId\":\"55073\",\"periodYear\":2026,\"periodMonth\":4,\"period\":\"2026-04-01\",\"status\":\"COMPLETED\",\"documentId\":98231,\"createdAt\":\"2026-05-01T00:00:50Z\"}"
}
The data field, parsed, has the following shape:
{
"statementRequestId": 4821,
"accountId": 943802,
"resourceType": "VBA",
"resourceId": "55073",
"periodYear": 2026,
"periodMonth": 4,
"period": "2026-04-01",
"status": "COMPLETED",
"documentId": 98231,
"createdAt": "2026-05-01T00:00:50Z"
}
| Field | Description |
|---|---|
statementRequestId | Unique identifier of the statement request. Use it with Get a Bank Statement to retrieve the download URL. |
accountId | Account ID that owns the statement. |
resourceType | The resource the statement was generated for. Currently always VBA. |
resourceId | The Virtual Bank Account funding method ID, as a string. |
periodYear | The statement year. |
periodMonth | The statement month (1–12). |
period | The statement period as a date (first day of the month). Format: YYYY-MM-DD. |
status | Final status of the statement. Possible values: COMPLETED, EMPTY, FAILED. |
documentId | Identifier of the generated statement document. Present when a PDF was produced. |
failureReason | Description of the failure. Present only when status is FAILED. |
createdAt | Timestamp when the statement was generated (ISO 8601). |
Retrieving the statement from a webhookThe webhook payload does not include the
downloadUrl. Use thestatementRequestIdfrom the payload to call Get a Bank Statement and obtain a fresh, short-liveddownloadUrl.
In addition to this event, refer to the Webhook Notification page for general webhook setup, and the Virtual Bank Account page for other VBA-related events.
Updated 9 minutes ago
