Transaction import API
Less than to read
This guide walks through the development requirements for a product integrating with Transaction Import (v1) directly through the exposed endpoints.
API flow diagram
Step 1. Obtain an access token
Before integrating with the Banking Service, integrate with the Authentication Service.
To work with Banking Service, you need an access token (JWT) from Authentication Service. The JWT is generated using the unique IDs of the organisation (organisationId) and company (companyId). This JWT can be provided as a bearer token for Banking Service requests through the authorisation header: ‘Bearer ‘.
Step 2. Create a ‘placeholder’ bank account
To use the transaction import functionality, a bank account needs to be created in the Banking Service. Follow the placeholder bank account guide to find out how to create an account.
Step 3. Get available file formats
When importing transactions into the Banking Service, the service needs to know what file type being imported. The Banking Service calls this the file format. The list of supported formats is provided by the fileformats endpoint. This returns a name, description and ID for each file format.
We recommend you allow users to select a file format from the list returned by the Banking Service. This means you can take advantage of new file formats as they’re added to the Banking Service.
GET /fileformats
Headers | Description | |
---|---|---|
<!– | x-application |
This is your application identifier which is generated from the Authentication Service. |
Authorization |
This is the bearer token returned from your request to the /accesstoken endpoint as described in step 1. | –> |
Content-Type |
This should be set as application/json. |
Response
{
"data": [
{
"fileFormat": "CSV#4col#v1",
"description": "CSV file with 4 columns",
"variant": "4col",
"version": 1,
"maxFileSize": 250000000,
"fileExtensions": [
"CSV"
],
"accountsSupported": "single"
}
],
"meta": {},
"error": null
}
Allow the option to download file templates
Banking Service provides file templates for users to download. They can use these templates to enter their data into before completing an import, or to check their own file against.
Step 4. Initiate the file import
When you’ve determined the file format that’s to be imported, the next step is to initiate the import. This is done by making a POST request to the imports endpoint. This creates an import attempt which generates a signed URL to be used to upload a file.
You need to pass the fileformat ID and the list of bank accounts to send the data to. What you need to send depends on the file format’s support for multiple bank accounts:
Single bank account file format
For most file formats you should only provide a single bank account and only need to provide the Banking Service ID (a UUID) for the bank account.
Multiple bank account file format
For file formats that support data for multiple bank accounts (for example CAMT053) you can provide 0 or more bank accounts. However you need to provide the account numbers (as recognised by the bank and contained in the import file) so the Banking Service knows where to put account transactions based on the information in the CAMT053 file.
When the file is submitted and an import report produced by the Banking Service, a list of the bank accounts and their account numbers will be available. You can decide to continue with the import and ignore the data from bank accounts that were not included in the list provided in the POST request.
Alternatively, you can abandon the import attempt. You need to establish which additional bank accounts should be included and create a new import attempt with these. Creating an import with no account identifiers listed provides a mechanism for discovering what bank accounts are available in the file.
If importing to multiple bank accounts from a single file, the bank accounts must all have been created in the same region. If this is not the case then you’ll get an error ‘Bank accounts must be processed separately’ with a list of the bank accounts that must be processed with a separate import.
At this stage the import will have a status of AwaitingFileUpload
.
POST /imports
Request body
{
data: {
source: 'test',
apiType: 'single',
fileFormat:"Tabular3column#v1",
fileName: "test",
// dataSource: 'AutoEntry',
bankId: pm.environment.get('_preset_consumer_bankId'),
description: "This is my description",
dateStyle: "bigEndian",
bankAccounts:[{
id: pm.environment.get('consumer_bankAccountId'),
countryCode: "GBR",
accountIdentifier: pm.environment.get('consumer_bankAccountId')
// bankIdentifier: pm.environment.get('consumer_indirect_bankIdentifier'),
// productDates: {
// transactionStartDate: "2021-02-11",
// transactionEndDate: "2021-02-11"
// }
}]
}
}
Response
{
"data": {
"id": "4760ec90-0ae3-4a6f-9f68-5d9f4b85bb3e",
"status": "awaitingFileUpload",
"importResponse": {
"_id": "4760ec90-0ae3-4a6f-9f68-5d9f4b85bb3e",
"companyId": "237fff2a-2820-4902-b089-d320befddc53",
"dateStyle": "bigEndian",
"fileFormat": "Tabular3column#v1",
"fileName": "test",
"description": "This is my description",
"bankAccounts": [
{
"id": "60faaf04-6bb1-4b31-b23c-ade85b680228",
"countryCode": "GBR",
"accountIdentifier": "60faaf04-6bb1-4b31-b23c-ade85b680228",
"transactionSign": "original"
}
],
"bankId": "168efa64-5317-4607-b1d5-1e66eb8c3cda",
"reviewLevel": "fullReview",
"source": "test",
"apiType": "single",
"fuzzyAccountMatching": false,
"bypassReplayValidation": false
}
},
"links": {
"uploadPath": "https://bnkc-transactionimport-dev01-eu-west-1-data.s3.eu-west-1.amazonaws.com/test/237fff2a-2820-4902-b089-d320befddc53/4760ec90-0ae3-4a6f-9f68-5d9f4b85bb3e?Content-Type=application%2Foctet-stream&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAZH7KSCFQINA7N5UN%2F20220817%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Date=20220817T100808Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEIL%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCWV1LXdlc3QtMSJHMEUCIAaUY4q0oOHYUmVJP6927CZ3Ne7tsMuNJQeGmcTRpNNJAiEAnnVFCEX5iT%2By1%2F75Tcv0H%2B5ModukKqpe7ray2U5HbMoqxgMI6%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARACGgw2MzU2MTAyMDY1NjAiDP%2FYdPHy3vSos8%2BjRCqaA6LmemGXqqYBnXpJv9PO0AvVEXhmEBJZPD4vIXyh5qCCfVdD24NTvNDSZH64bWmTkrNhu7FG2%2F%2BMJD7Fm2mosIi8FuwqIVE7NQq60ERKRsr%2F3%2BEqoKtudgvKqWBaDYxonOMSzjBJZT30uY0MVQlJ4vDNQMdqwEJ%2Fq6cWlcvgIshEbV3R490LSG2YOqMtECMguG7v%2BaMx6JxpfpdDtMorI3l7E0KDAWch8YwrUpGxUYapoiXPDVniJDQ%2Bopq%2BkJZZtedtj07%2BmUKHmlK5T8gy%2F43l6%2FkCtGfjdgwSbm1bX11yX44KwzCPM86ERvY9PkDcf0eBzOlxwe%2BWOGkfNw%2BehIjSK7OQgN511X4Vct818iaNEz19fyK4%2B%2BxzYeW%2FXo8qlMs8k0ulm%2FXJ0F90CpASNBzYOILHnSJlRufJ7t5yJpq9%2B7LHGErigMGDiMh56HHwW2cyibBkI4cd9mBxUWntm%2B09IUipRylk6cXPDjCBnZzQF2ED3KdanDetFDeKF6Ey67Niq%2B2B8tD5YvZhL9WKYZwPaLhqv57Ry6DQMIf88pcGOp4BTnb9zVr9o%2FIMltBpzuJCIP5RDN%2BvW8SWZvwrtaIskdH8XFFlwm3RvmaRL4XpPKTWEmKiCEgv3nLSNDUTgr6Jqm7X1kTELW7atPuy7guVxtwjKGX1nCKxDFkcC1KfzJisTaxb7QnZMZmOOj8Mc%2Bh6M%2BpHT5pPPk7p%2F8jzOLtuE84oDti1a6XOFQSaDZ4%2FRtIv6dXfOO6%2F%2FM9TFABuYoA%3D&X-Amz-Signature=ae493a66d7fdce55054d624ca13598ee42fc8c58ad62971ded127987d4c03384&X-Amz-SignedHeaders=host"
},
"meta": {},
"error": null
}
Step 5. Upload the file
The response from the POST request in step 4 will return a signed URL. This can be used to upload the file. The signed URL is valid for 15 minutes. If there is any significant delay between the POST and the attempt to upload the file then you should perform a GET on the import resource to request a fresh signed URL.
To upload the file using the signed URL go to the AWS Instructions. For large files (over 100MB) you should use a multi-part upload (instructions TBD).
When the upload is complete, the status of the import will move to Processing
.
PUT {uploadPath}
Request Body
Attach the file in the body of this request. The file will need to fit the specifications set in the intial call or errors will be thrown.
Response
Status 200 OK
Step 6. Poll until confirmation (or error)
When a file has been uploaded to the generated upload URL, you should perform a continuous poll until the status of the transaction import is either ‘awaitingConfirmation’ or ‘error’. Read more about state machine statuses.
A query parameter ?include=report should be used at this stage to ensure that the import report is returned if it is available. The import report will be available when the import has moved beyond the Processing state to either AwaitingConfirmation
or Error
.
GET /imports/{importId}
Response
{
"data": {
"validationDetails": [],
"fileName": "test",
"companyId": "237fff2a-2820-4902-b089-d320befddc53",
"reviewLevel": "fullReview",
"fileFormat": "Tabular3column#v1",
"s3FilePath": "test/237fff2a-2820-4902-b089-d320befddc53/229c6267-4187-4f52-b0c2-3678f79d7520",
"status": "awaitingConfirmation",
"dateStyle": "bigEndian",
"bankAccounts": [
{
"accountIdentifier": "60faaf04-6bb1-4b31-b23c-ade85b680228",
"id": "60faaf04-6bb1-4b31-b23c-ade85b680228",
"transactionSign": "original",
"countryCode": "GBR"
}
],
"fuzzyAccountMatching": false,
"statement": {
"summary": {
"accountDetailsCount": 1,
"transactionRangeStartDate": "2004-10-11T11:30:00.000Z",
"transactionCreditSum": 5220,
"transactionCreditCount": 2,
"transactionDetailsCount": 5,
"transactionDateOverlapCount": 0,
"transactionDebitSum": -11000,
"transactionRangeEndDate": "2004-10-15T11:30:00.000Z",
"transactionDebitCount": 3
},
"id": "70f29b27-c49f-487b-bc4d-219e3b781f7e"
},
"executionArn": "arn:aws:states:eu-west-1:635610206560:execution:bnkc-transactionimport-dev01-eu-west-1-Step:0e699cfd-be10-1e42-cefb-aa78dfdbe2d5_17469358-ae02-1c79-e72c-929bbb110c5a",
"bankId": "168efa64-5317-4607-b1d5-1e66eb8c3cda",
"bypassReplayValidation": false,
"_id": "229c6267-4187-4f52-b0c2-3678f79d7520",
"statusMonitor": {
"pollFirstAttempt": "2022-08-17T10:21:36.811Z",
"pollAttempts": 10,
"pollLastAttempt": "2022-08-17T10:23:14.019Z"
},
"fileUploaded": true,
"validationDetailsCount": 0,
"organisationId": "f5a9de10-4d8a-44ca-b27a-c364c8c0199b",
"created": "2022-08-17T10:20:21.945Z",
"updated": "2022-08-17T10:20:21.945Z",
"accountIdentifiers": [],
"errorDetails": [],
"description": "This is my description",
"sourceProduct": "sage.integrate.myproduct",
"apiType": "single"
},
"links": null,
"meta": {},
"error": null
}
Example of a response with error
```json
{
"data": {
"validationDetails": [],
"fileName": "newImport",
"companyId": "237fff2a-2820-4902-b089-d320befddc53",
"reviewLevel": "fullReview",
"fileFormat": "JSON#v0",
"s3FilePath": "test/237fff2a-2820-4902-b089-d320befddc53/a6556b59-689b-4040-aec7-7953183f222b",
"status": "error",
"dateStyle": "littleEndian",
"bankAccounts": [
{
"accountIdentifier": "JEFF2",
"id": "60faaf04-6bb1-4b31-b23c-ade85b680228",
"transactionSign": "original",
"countryCode": "GBR",
"bankIdentifier": ""
}
],
"fuzzyAccountMatching": true,
"executionArn": "arn:aws:states:eu-west-1:635610206560:execution:bnkc-transactionimport-dev01-eu-west-1-Step:2fdb8479-016c-e45e-b3e1-3c1c305e5077_a9a498e9-e3a7-ef80-7a5f-14005ec2b485",
"bankId": "168efa64-5317-4607-b1d5-1e66eb8c3cda",
"bypassReplayValidation": false,
"_id": "a6556b59-689b-4040-aec7-7953183f222b",
"fileUploaded": true,
"validationDetailsCount": 0,
"organisationId": "f5a9de10-4d8a-44ca-b27a-c364c8c0199b",
"created": "2022-08-17T09:26:15.822Z",
"updated": "2022-08-17T09:26:15.822Z",
"errorDetails": [
{
"severity": "error",
"message": "Failed to parse file",
"code": "ProcessingError"
}
],
"description": "This is my description",
"sourceProduct": "sage.integrate.myproduct",
"apiType": "multi"
},
"links": null,
"meta": {},
"error": null
}
```
Retrieve error details
If an error is recieved you can call the error details endpoint for detailed information on why it occured. This will also detail any warnings the Banking Service has identified. This should be presented to the user to make the necessary corrections.
GET /imports/{importId}/errordetails
Response
{
"data" : [ {
"code" : "RequiredValueMissing",
"actualValue" : "actualValue",
"message" : "Invalid postcode: postcode must 8 characters long in the format NE13 9AA",
"lineNumber" : 1,
"target" : "$['toplevel']['nextlevel'][0].['postcode']"
}, {
"code" : "RequiredValueMissing",
"actualValue" : "actualValue",
"message" : "Invalid postcode: postcode must 8 characters long in the format NE13 9AA",
"lineNumber" : 1,
"target" : "$['toplevel']['nextlevel'][0].['postcode']"
} ]
}
Step 7. Review transactions
When the status of this import has reached awaitingConfirmation
, you should use the review transactions endpoint to display the uploaded transactions. This allows the user check the transactions which are about to be imported.
When making a transaction import request, the user can request the type of review level they wish to use. Read the review level guide for details.
GET /imports/{importId}/reviewtransactions
Headers | Description |
---|---|
x-application |
This is your application identifier which is generated from the Authentication Service. |
Authorization |
This is the bearer token returned from your request to the /accesstoken endpoint as described in step 1. |
Content-Type |
This should be set as application/json. |
Query Parameters | Description |
---|---|
pageSize |
This is the amount of transactions you would like to return within this request, for example, 100. |
Response
{
"data": [
{
"transactionId": "2004-10-11T11:30:00.000Z-52e6d2e9f340191575ce40af438ec77a9679b5dda75f56d491eb5b49d9d28cb9-60faaf04-6bb1-4b31-b23c-ade85b680228-1-1",
"bankAccountId": "60faaf04-6bb1-4b31-b23c-ade85b680228",
"transactionAmount": -5000,
"transactionType": "DEBIT",
"datePosted": "2004-10-11T11:30:00.000Z",
"description": "Shoe purchase",
"possibleDuplicate": false
},
{
"transactionId": "2004-10-12T11:30:00.000Z-52e6d2e9f340191575ce40af438ec77a9679b5dda75f56d491eb5b49d9d28cb9-60faaf04-6bb1-4b31-b23c-ade85b680228-1-2",
"bankAccountId": "60faaf04-6bb1-4b31-b23c-ade85b680228",
"transactionAmount": -5000,
"transactionType": "DEBIT",
"datePosted": "2004-10-12T11:30:00.000Z",
"description": "Shoe purchase another pair",
"possibleDuplicate": false
},
{
"transactionId": "2004-10-13T11:30:00.000Z-52e6d2e9f340191575ce40af438ec77a9679b5dda75f56d491eb5b49d9d28cb9-60faaf04-6bb1-4b31-b23c-ade85b680228-1-3",
"bankAccountId": "60faaf04-6bb1-4b31-b23c-ade85b680228",
"transactionAmount": 5000,
"transactionType": "CREDIT",
"datePosted": "2004-10-13T11:30:00.000Z",
"description": "Shoes refund",
"possibleDuplicate": false
},
{
"transactionId": "2004-10-14T11:30:00.000Z-52e6d2e9f340191575ce40af438ec77a9679b5dda75f56d491eb5b49d9d28cb9-60faaf04-6bb1-4b31-b23c-ade85b680228-1-4",
"bankAccountId": "60faaf04-6bb1-4b31-b23c-ade85b680228",
"transactionAmount": -1000,
"transactionType": "DEBIT",
"datePosted": "2004-10-14T11:30:00.000Z",
"description": "T-shirt purchase",
"possibleDuplicate": false
},
{
"transactionId": "2004-10-15T11:30:00.000Z-52e6d2e9f340191575ce40af438ec77a9679b5dda75f56d491eb5b49d9d28cb9-60faaf04-6bb1-4b31-b23c-ade85b680228-1-5",
"bankAccountId": "60faaf04-6bb1-4b31-b23c-ade85b680228",
"transactionAmount": 220,
"transactionType": "CREDIT",
"datePosted": "2004-10-15T11:30:00.000Z",
"description": "Coffee purchase refund",
"possibleDuplicate": false
}
],
"links": {},
"meta": {
"transactionCount": 5,
"creditCount": 2,
"debitCount": 3,
"dateOverlapCount": 0
},
"error": null
}
Step 8. Verify transactions (optional)
Before confirming transactions, there is the option to review the transactions that are being imported and to request that the sign of all transactions be reversed (“flipped”). This is an optional step which can be used to verify which transactions indicate money coming in and out of an accout. Transactions that were marked as credits will become debits and debits will become credits.
The option to flip transactions applies at a bank account level. This means if a transaction import file includes multiple bank accounts, then the update transactions endpoint will allow for some accounts to be reversed, and others to retain their original sign.
Calling the update transactions endpoint will go through the same flow of importing the transactions again. However, the credit or debit transactionType will be flipped.
GET /imports/{importId}/amendtransactions
Headers | Description |
---|---|
x-application |
This is your application identifier which is generated from the Authentication Service. |
Authorization |
This is the bearer token returned from your request to the /accesstoken endpoint as described in step 1. |
Content-Type |
This should be set as application/json. |
Request body
{
data: {
flipTransactions: {
bankAccountIds: [60faaf04-6bb1-4b31-b23c-ade85b680228]
}
}
}
Response
Status 204 No content
How does the Banking Service UI handles transaction verification?
We recommend showning the user a single transaction taken from their file and asking them to identify if this transction represents money coming in or out of their account. Based on the user’s selection, you can flip all signs from positive to negative (and the reverse) to ensure the other transactions are in the correct format.
Banking Service verify transaction screen - Example.
7. Confirm transaction import
When you’re happy for the import to go ahead you can issue a POST request to the confirm endpoint. When this request has been made it is not possible to undo the import in Banking Service.
POST /imports/{importId}/confirm
Headers | Description |
---|---|
x-application |
This is your application identifier which is generated from the Authentication Service. |
Authorization |
This is the bearer token returned from your request to the /accesstoken endpoint as described in step 1. |
Content-Type |
This should be set as application/json. |
Response
Status 204 No Content
Step 9. Poll until confirmation (or error)
After you’ve called the POST /confirm endpoint, you should perform another continuous poll until the transaction import status is either ‘complete’ or ‘error’. Requesting the import report or uploadUrl is not recommended at this stage.
GET /imports/{importId}
Headers | Description |
---|---|
x-application |
This is your application identifier which is generated from the Authentication Service. |
Authorization |
This is the bearer token returned from your request to the /accesstoken endpoint as described in step 1. |
Content-Type |
This should be set as application/json. |
When you’ve confirmation this stage is complete, you can use the normal GET /transactions endpoint on the relevant bank accounts to obtain the imported transactions with any rules applied.
Step 10. Obtain list of a users current and historical imports
The API allows products to retrieve a list of current and historical imports for the user to reference.
GET /imports
Response
{
"data": [
{
"validationDetails": [],
"fileName": "newImport",
"companyId": "237fff2a-2820-4902-b089-d320befddc53",
"reviewLevel": "fullReview",
"fileFormat": "JSON#v0",
"s3FilePath": "test/237fff2a-2820-4902-b089-d320befddc53/a6556b59-689b-4040-aec7-7953183f222b",
"status": "deleted",
"dateStyle": "littleEndian",
"bankAccounts": [
{
"accountIdentifier": "JEFF2",
"id": "60faaf04-6bb1-4b31-b23c-ade85b680228",
"transactionSign": "original",
"countryCode": "GBR",
"bankIdentifier": ""
}
],
"fuzzyAccountMatching": true,
"executionArn": "arn:aws:states:eu-west-1:635610206560:execution:bnkc-transactionimport-dev01-eu-west-1-Step:2fdb8479-016c-e45e-b3e1-3c1c305e5077_a9a498e9-e3a7-ef80-7a5f-14005ec2b485",
"bankId": "168efa64-5317-4607-b1d5-1e66eb8c3cda",
"bypassReplayValidation": false,
"_id": "a6556b59-689b-4040-aec7-7953183f222b",
"fileUploaded": true,
"validationDetailsCount": 0,
"organisationId": "f5a9de10-4d8a-44ca-b27a-c364c8c0199b",
"created": "2022-08-17T09:26:15.822Z",
"updated": "2022-08-17T09:26:15.822Z",
"errorDetails": [
{
"severity": "error",
"message": "Failed to parse file",
"code": "ProcessingError"
},
{
"severity": "info",
"message": "deleted TransactionImport"
}
],
"description": "This is my description",
"sourceProduct": "sage.integrate.myproduct",
"apiType": "multi"
},
{
"validationDetails": [],
"fileName": "newImport",
"companyId": "237fff2a-2820-4902-b089-d320befddc53",
"reviewLevel": "fullReview",
"fileFormat": "XML#OFX#v1",
"s3FilePath": "test/237fff2a-2820-4902-b089-d320befddc53/ea10d58b-16bc-4480-9e82-8cf05d62f575",
"status": "error",
"dateStyle": "littleEndian",
"bankAccounts": [
{
"accountIdentifier": "badger",
"id": "60faaf04-6bb1-4b31-b23c-ade85b680228",
"transactionSign": "original",
"countryCode": "GBR",
"bankIdentifier": ""
}
],
"fuzzyAccountMatching": true,
"executionArn": "arn:aws:states:eu-west-1:635610206560:execution:bnkc-transactionimport-dev01-eu-west-1-Step:bb2c1bd7-938e-e625-3ffc-5412eda7c792_b99a2d91-6693-ab40-46cb-ec1e1a52da9a",
"bankId": "168efa64-5317-4607-b1d5-1e66eb8c3cda",
"bypassReplayValidation": true,
"_id": "ea10d58b-16bc-4480-9e82-8cf05d62f575",
"fileUploaded": true,
"validationDetailsCount": 0,
"organisationId": "f5a9de10-4d8a-44ca-b27a-c364c8c0199b",
"created": "2022-08-17T09:37:36.132Z",
"updated": "2022-08-17T09:37:36.132Z",
"errorDetails": [
{
"severity": "error",
"code": "InvalidSourceData",
"message": "Invalid data",
"target": "File"
},
{
"severity": "error",
"message": "One or more fields were missing, or failed to match the required specification",
"code": "ValidationError"
}
],
"description": "This is my description",
"sourceProduct": "sage.integrate.myproduct",
"apiType": "single"
}
],
"links": {},
"meta": {},
"error": null
}
Step 11. Deleting imports
Imports can be deleted using the DELETE /imports/{id} endpoint. They can only be deleted in the states awatingConfirmation
, completed
or error
. Imports will automatically be deleted after 12 months. However, applications are encouraged to delete imports as soon as the user is finished with them.
DELETE /imports/{importId}
Recap
In this walkthrough we’ve gone through the process of integrating with the transaction import funtionaility directly through the endpoints available on the Banking Service Consumer API.