Skip to content
Developerhome

Posting statements

  Less than to read

This walkthrough covers how to use the statements flow to upload transaction data to Banking Service through the Provider API. We’ll cover the API calls made to and from Banking Service from your application and consuming product to demonstrate the posting statements flow. This is detailed in our Postman collection.


Overview

  1. Statements are uploaded individually for each bank account.
  2. While multiple bank accounts can be processed simultaneously, only one statement from each account can be processed at the same time. Providers should loop through all transactions they want to send for a given account. Sending a single batch and then polling for its completion before sending the next.
  3. Bank accounts will remain in a ‘pending’ status until the first transactions have been posted by the provider.

API flow diagram

Flow diagram displaying the authorisation flow

Participant description
  • Product The Sage product which is currently integrated with Banking Service UI using Consumer API.
  • UI The user interface which allows the Sage user to search for a bank and allows them to authenticate.
  • Banking Service Banking Service handles the calls from the consuming API which Sage products use to interact with Banking Service. Also handling the provider API which handles the connection from any 3rd party provider.
  • Sage ID Sage ID is used to secure all requests into the Provider API. You will use Sage ID to obtain your access token.
  • Provider This refers to the 3rd party who is integrating with Banking Service. This 3rd party connector will need to contain the connector API endpoints to be able to handle the Banking Service flows and recieve data.

Statement requirements

We ask that statements sent into Banking Service through the provider API meet the following requirements:

  • Only cleared transactions are sent.
  • Transactions are recommended to be sent daily.
  • Send transactions in the order they appear on the account statement.
  • User can select a start date they would like to recieve transactions from.
  • Each transaction should have a unique identifier. The identifier for a transaction must never change. The same transaction identifier should not occur more than 1 time for a bank account. Statements containing transaction IDs that have been sent previously will return an error and will not be processed. It is safe to resubmit a statement if there’s uncertainty around a previous delivery. For example, connection times out before a response is received, 500 error.
  • Each upload containing transactions must have a correctly signed ending balance. This will be positive or negative.
  • You can only submit 1 statement at a time for a bank account. The HTTP response for the first statement must be received before submitting further statements.
  • Support filtering transactions so that only posted or cleared transactions are sent to Provider API. Banking Service does not support pending or uncleared transactions.
  • Have the ability to page requests to Provider API. Each statement can contain up to 1,000 transactions. If more than this are available for a bank account, they must be sent in multiple requests.
  • Support rolling balances. You must send balances with each statement. The balance must equal the previous balance, plus the total of the transactions being sent.
  • Support the minimum set of required data, you can find out more in Provider API. The minimum dataset is:
    • Amount
    • Type (for example: credit, debit, direct debit, interest)
    • Date posted
    • Status
    • Description
    • narrative1
    • narrative2
    • name/description
    • referenceNumber
    • payee.payeeDescription
    • `checkNumber

1. Get an access token

Using the Provider API to complete requests requires a Sage ID bearer token and an API key to authenticate the call.

An API key will be provided to you by Sage through the setup proccess. To Generate a Sage ID bearer token you can make a POST request to the token endpoint as detailed below. This token generally lasts 480 minutes but should be refreshed when receiving a 401 Unauthenticated responses from the API.

POST /oauth/token

Sage IDProvider -> Sage ID

This request should be sent with the following body:

Body parameters Description
grant_type This should be set as client_credentials.
client_id This value identifies your client, and is tied to your provider; only tokens generated with your clientId can access resources associated with your provider.
client_Secret This value is required in order to generate Sage ID tokens. It should be handled as a secret and not shared.
audience This value identifies the Provider API and ensures that generated SageId tokens are targeted at the correct API.

These resources (keys) will be supplied by Sage.


2. Push transactions

The /statements POST endpoint is used to initialise processing of data for a single BankAccount. The body of the request can include up to 1,000 TransactionDetails objects, along with a single AccountDetails object. Some initial data validation checks will be performed; but full processing of the payload will happen asynchronously.

Transactions should be sent in the same order as they appear on the account statement. This means you should post the first 1,000 statements in date order and wait until this has been successful until moving onto the next 1,000. If an error occurs on this first POST, you would need to retry and confirm the status has been successful before moving on.

Processing progress can be tracked using the /statements/{statementId} GET endpoint.

:

Any given BankAccount can only have 1 statement in flight at a time. This avoids concurrency issues with the submission and validation of the data. This means a provider must wait for the response from the first request before making a second request for that BankAccount.

:

When onboarding the user selects their requested start date, it’s sent to the provider in the bank account created notification. The provider should use this as the start date of transactions sent into the Banking Service for this account.

When TransactionDetails are sent, the AccountDetail balances must represent the account balances after these transactions are applied. The status and balances can be updated independent of TransactionDetails by sending 0 TransactionDetails objects.

POST /statements

Provider APIProvider -> Banking Service

Headers Description
x-api-key This value required in validating calls to the Provider API. It should be handled as a secret and not shared. Individual keys of the API may be throttled depending on usage agreements.
Authorization This is the value returned from your call to the /oauth/token endpoint.
Content-Type This should be set as application/json.

Example request body:

{
    "data": {
        "bankId" : "29e94a6d-215e-4f9d-b207-83be8f7d845d",
        "accountDetails": [{
            "bankAccountId": "92c7bce5-3c01-4899-ab77-a5ecf85d6ff8",
            "status": "active",
            "balances": {
                "ledgerBalance": 0,
                "ledgerBalanceDate": "2019-11-24T12:00:00.000Z",
                "availableBalance": 0,
                "availableBalanceDate": "2019-11-24T12:00:00.000Z"
            }
        }],
        "transactionDetails": [{
            "uniqueId": "1",
            "bankAccountId": "92c7bce5-3c01-4899-ab77-a5ecf85d6ff8",
            "transactionAmount": 111,
            "transactionType": "CREDIT",
            "transactionStatus": "posted",
            "datePosted": "2019-11-02T23:00:12.000Z",
            "dateUserInitiated": "2019-11-04T22:54:00.000Z",
            "exchangeCurrency": "EUR",
            "exchangeAmount": 120,
            "checkNumber": "123456",
            "referenceNumber": "00000001",
            "description": "test_description",
            "payee": {
                "payeeDescription": "100001",
                "address1": "1 the something",
                "address2": "on some street",
                "address3": "on some estate",
                "city": "in a city",
                "state": "in a state",
                "postalCode": "MY POST CODE",
                "country": "GBR",
                "phoneNumber": "0091299291212",
                "payeeBankId": "123456",
                "payeeAccountId": "654321"
            },
            "coordinates": {
                "lat": 0.9812,
                "long": 1.0238
            },
            "narrative1": "narrative data",
            "narrative2": "extended narrative data",
            "category": {
                "topLevelCategory": "TopCategory",
                "subCategory": "SubCategory",  
                "categoryId": 12,
                "standardIndustrialCode": "9089"
            }
        }],
        "principalId":"92c7bce5-3c01-4899-ab77-a5ecf85d6ff8",
             "expected": {
              "transactionDetailsCount": 1,
              "accountDetailsCount": 1,
              "transactionCreditSum":111,
              "transactionDebitSum": 0
          }
    }
}

Descriptions of request body identifiers:

  • bankId - The identifier of the bank which this statement is for.
  • principalId – This is the bankAccountId. This is created by the Banking Service and passed to you as the resource ID in the resource created (bank account created) notification once a customer has successfully onboarded an account.
  • uniqueId – This is a unique identifier of this transaction. This uniqueId should never match another transaction. If this transaction were to be posted again, the uniqueId needs to be the same.
  • transactionAmount - This should be an integer which equals the amount of the transaction in minor units, including signage.

Transaction Import/Polling Times

The following table presents the results from some load tests. The tests measured the time required to process different numbers of transactions from both a cold start and a warm start.

Number of transactions Time to process from a cold start Time to process from a warm start
50 20 seconds 18 seconds
100 43 seconds 20 seconds
200 42 seconds 18 seconds
500 46 seconds 22 seconds
1000 46 seconds 25 seconds

3. Poll until succeeded

After posting your transactions through the POST /statements endpoint. You should check to ensure the transactions have succesfully been processed. This can be done by continuing to poll the GET /statements request using the statement ID returned from the previous call to POST /statements. In the response to this GET request you will find the status property. This can be used to identify the current processing state.

If the status is set to succeeded the processing is complete and the consuming Sage product will be able to retrieve these transactions. If it’s set to processing the service is in the middle of handling this request. This may be down to being busy or handling a large number of transactions.

The following are the possible returned status results when attempting to push your transactions:

  • accepting: Banking Service is accepting accountDetail and transactionDetail parts. The delete statement endpoint can be called by the provider.
  • queued: The transaction post request is queued for processing, and can no longer accept parts.
  • processing: The batch is being processed.
  • succeeded: The batch was processed successfully with no errors (may still contain warnings).
  • failed: The batch failed to process successfully and has errors. The delete statement endpoint should be called by the provider.
  • deleted: The batch has been deleted by the provider.

GET /statements

Provider APIProvider -> Banking Service

Headers Description
x-api-key This value required in validating calls to the Provider API. It should be handled as a secret and not shared. Individual keys of the API may be throttled depending on usage agreements.
Authorization This is the value returned from your call to the /oauth/token endpoint.
Content-Type This should be set as application/json.

Example response:

{
    "data": {
        "principalId": "fe5538b6-5570-4e67-8dde-f5ff5f2f4373",
        "expected": {
            "transactionDetailsCount": 1,
            "accountDetailsCount": 1,
            "transactionCreditSum": 111,
            "transactionDebitSum": 0
        },
        "actual": {
            "transactionDetailsCount": 1,
            "accountDetailsCount": 1,
            "transactionCreditSum": 111,
            "transactionDebitSum": 0
        },
        "status": "queued",
        "statusReason": "This Batch is queued for processing",
        "statusModifiedDate": "2019-11-27T07:55:34.021Z",
        "providerId": "fe5538b6-5570-4e67-8dde-f5ff5f2f4373",
        "_id": "d578ace1-920a-4988-9698-47e51ba3591e"
    },
    "links": {
        "self": ""
    },
    "meta": null,
    "error": null
}

The consuming Sage product can then make a request to the GET /transactions endpoint, allowing the customer to access these new transactions.

:

Note: The time transactions take to show up within the UI depends on the consuming product. Each products determines how they wish to download transactions retrieve the transactions, this can either be on a schedule, when the user logs in, when a user manually selects to download the latest transactions or a combination of all three. We are unable to specify how long it would take for each product.


Test posting statements

Test description Expected outcome
A customer needs to be able to retrieve transactions. After your service posts statements through the provider API POST /statements endpoint, they should be available to the consuming product through the consumer API GET /transactions call.
You should not be able to post the same set of transactions twice. When a transaction status returns as ‘failed’ with details code ‘DuplicateTransaction’, you should handle this and only send transactions which have not previously been provided.

FAQs

How long does it take for transactions to show in product?
The time transactions take to show up in the UI depends on the consuming product. Each product determines how they wish to retrieve the transactions, this can either be on a schedule, when the user logs in, when a user manually selects to download the latest transactions or a combination of all 3. We cannot specify exactly how long it would take for each product.
What needs to happen if a statement fails?
Should a statement you POST get set to failed, it will not be possible to POST another statement until the issue is resolved. When the issue is resolved the failed statement can be deleted through the use of the delete endpoint. This allows the Statement POST to then be retried. If you attempt to POST another statement without deleting the failed you would recieve a 409 Exception. An example on when a statement might fail is when a duplicate transaction is detected.

Recap

This walkthrough has covered the Banking Service flow for posting transactions. Covering how the provider can push transaction data into Banking Service through the /statements endpoint, and how to ensure they have been processed successfully before posting the next batch. How the provider can authenticate their requests through the Provider API by retrieving a Sage ID bearer token has also been covered.


What’s next?

Next, take a look at the offboarding flow. This covers how to disconnect an account.


Was this helpful?