Guides • Build Banking Apps
Create a file payment
doc

Create a file payment

This tutorial presents how to create a file payment, which allows you to initiate a transaction batch with a single consent.

note

File payments are available only for Revolut Business users.

The procedure is similar to the procedure for other payment endpoints, but it includes additional steps and considerations required to upload the batch files.

Prerequisites

Before you begin, ensure that you have:

  • Registered your application with the payments scope in the Developer Portal
  • Obtained a sandbox/production client_id from the Developer Portal
  • Obtained sandbox/production transport.pem and signing.pem certificates, from the Developer Portal or QTSP issuing body
  • Uploaded the jwks_url in the Developer Portal that is specific to your transport.pem certificate. Ensure that the x5c claim is specified.
tip

If unsure, head to Get Started and review the setup process.

1. Create a file payment CSV

A file payment CSV contains all the payments that you want to initiate in a batch. It consists of the following fields, separated by a comma (,):
FieldRequiredDescription
NameYesCan contain up to 80 characters. If recipient type is INDIVIDUAL, this field must contain a first and a last name, separated by a space.
Recipient typeYesCan be either INDIVIDUAL or COMPANY.
Account numberFor non-IBAN countriesMust contain valid account number if provided.
Sort code or Routing numberFor UK/US local transfersMust contain valid sort code or routing number if provided.
IBANFor IBAN countriesMust contain valid IBAN if provided.
BICAll the countries except for UK/US localMust contain valid BIC if provided.
Recipient bank countryYesMust contain a valid ISO 3166-1 country code.
CurrencyYesMust contain valid ISO 4217 currency code.
AmountYesMust match the following pattern [0-9]*(\.[0-9]*)?.
Payment referenceYesCan contain up to 100 characters.
Recipient countryNoMust contain a valid ISO 3166-1 country code if provided.
State or provinceNoCan contain up to 50 characters.
Address line 1NoCan contain up to 50 characters.
Address line 2NoCan contain up to 50 characters.
CityNoCan contain up to 50 characters.
Postal codeNoCan contain up to 50 characters.

For the purpose of this tutorial, we will use the following sample file contents and save it as file.csv:

Name,Recipient type,Account number,Sort code or Routing number,IBAN,BIC,Recipient bank country,Currency,Amount,Payment reference,Recipient country,State or province,Address line 1,Address line 2,City,Postal code
John Smith,INDIVIDUAL,40513598,207409,,,GB,GBP,10,First comment,GB,,Revolutest LTD,Somewhere in London,London,E14 5AB
John Doe,INDIVIDUAL,90352556,600001,,,GB,GBP,10,Second comment,GB,,Revolutest LTD,Somewhere in London,London,E14 5AB
note

If you use your own CSV file, remember to replace the file name later when you compute the hash.

2. Compute the hash of the CSV file

Compute the SHA256 hash of the CSV file. To do it from a Command Line Interface (CLI), follow these steps:

  1. Open the CLI, for example, Terminal in macOS.

  2. In your CLI, navigate to the directory in which you saved the CSV file.

  3. Compute the SHA256 hash of your CSV file. If you're using your own CSV file, replace file.csv with your file's name.

    cat file.csv | shasum -a 256 | xxd -r -p | base64
Expected result

The above command returns the SHA256 hash of the CSV file. For our sample file.csv, this would be:

2nDGfxr0OI5+ts/iz9/+mk3VYTxhamlWA3P65a5LuKs=

Save the resulting hash for further steps.

info

The resulting hash will be different with any minor modification to the file, so it uniquely identifies the contents of the file.

3. Generate a client credentials token

Request an access token for client credentials using the /token endpoint and the client_credentials grant type with the scope payments:

curl --cert transport.pem --key private.key \
--location --request POST 'https://oba-auth.revolut.com/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'scope=payments' \
--data-urlencode 'client_id=<your client_id>'

Response:

{
"access_token": "<JWT client credentials>",
"token_type": "Bearer",
"expires_in": 2399
}

You can use this token to:

note

When your token expires and you need a new one, repeat this procedure to generate a new token.

Create a consent to initiate a file payment on behalf of a Revolut customer.

When you create the consent, ensure that you:

  • Use your access token that you obtained with grant_type=client_credentials as the Bearer token.

  • Specify the x-idempotency-key header so that when there is a network failure and you do not receive the ID from the response, you can safely retry the request.

  • Provide the x-jws-signature header in the API request.

    It must contain a valid JSON Web Signature (JWS) of the request payload body. When generating the signature, use the following JSON header:

    {
    "alg": "PS256",
    "kid": "<kid parameter of your signing certificate>",
    "crit": ["http://openbanking.org.uk/tan"],
    "http://openbanking.org.uk/tan": "<root domain of your JWKS URL>"
    }

    The result is a string consisting of the above header in base64 encoding, followed by two dots and the cryptographic signature.

    warning

    The signature in the JWS validates the header and payload as text, so make sure the payload used when generating the signature is exactly the same as the payload sent in the request payload, including JSON formatting, line breaks and spacing.

    You can read more about JSON Web Signatures here.

Make a file payment consent request. An example request looks like this:

curl --location --request POST 'https://oba.revolut.com/file-payment-consents' \
--header 'x-fapi-financial-id: 001580000103UAvAAM' \
--header 'Content-Type: application/json' \
--header 'x-idempotency-key: 123' \
--header 'Authorization: Bearer <insert JWT client credentials from step 3.>' \
--header 'x-jws-signature: <insert JWS>' \
--data '{
"Data": {
"Initiation": {
"FileType": "text/csv",
"FileHash": "2nDGfxr0OI5+ts/iz9/+mk3VYTxhamlWA3P65a5LuKs=",
"FileReference": "reference1234"
}
}
}

Response:

{
"Data": {
"Status": "AwaitingUpload",
"StatusUpdateDateTime": "2023-11-08T16:23:57.491851Z",
"CreationDateTime": "2023-11-08T16:23:57.491851Z",
"ConsentId": "f3e5d778-a0b6-48c5-bae2-886f0097d51f",
"Initiation": {
"FileType": "text/csv",
"FileHash": "2nDGfxr0OI5+ts/iz9/+mk3VYTxhamlWA3P65a5LuKs=",
"FileReference": "reference1234"
}
},
"Links": {
"Self": "https://oba.revolut.com/file-payment-consents/f3e5d778-a0b6-48c5-bae2-886f0097d51f"
},
"Meta": {
"TotalPages": 1
}
}

For the full list of available parameters and other details:

See the API reference: Create a file payment consent

Expected result

The consent has been created, and the CSV file has been loaded.

The ID of the created consent (Data.ConsentId) is returned in the response. Copy this value, as you will need it for further steps. In our example, the obtained consent ID is f3e5d778-a0b6-48c5-bae2-886f0097d51f.

5. Upload the CSV file

After the consent has been successfully created, you must upload the CSV file in a separate request.

note
  • Use the same access token that you obtained with grant_type=client_credentials as the Bearer token.
  • Use the ConsentId obtained after creating the consent.
  • To calculate the x-jws-signature header parameter, use the same process as described in the previous step and provide the content of the CSV file as the payload.
  • In the request body, provide the local path to where the CSV file that you're uploading is located on your machine. For example: --data '@/Users/john.doe/Desktop/file.csv'.
curl --location 'https://oba.revolut.com/file-payment-consents/<insert ConsentId from step 4.>/file' \
--header 'x-fapi-financial-id: 001580000103UAvAAM' \
--header 'Content-Type: text/csv' \
--header 'x-idempotency-key: 123' \
--header 'Authorization: Bearer <insert JWT client credentials from step 3.>' \
--header 'x-jws-signature: <insert JWS>' \
--data '@<insert full path to your CSV file>'

For the full list of available parameters and other details:

See the API reference: Upload a payment file

Expected result

On successful upload, you receive an empty JSON object as a response:

{}

6. Create a JWT URL parameter

After you create a consent, you need the user to authorise the consent so that you can initiate a payment on their behalf.

Create a JWT request parameter with the following header and payload. Use the private key corresponding to your signing certificate. This signature will be validated using the JWKS endpoint that you specified when you registered your application.

caution

The values of client_id, redirect_uri, kid, and scope should correspond to those for your specific application and consent request.

The value of openbanking_intent_id is the value of the ConsentId field returned in the consent creation response.

Header:

{
"alg": "PS256",
"kid": "<insert kid>"
}

Body:

{
"response_type": "code id_token",
"client_id": "<insert client_id>",
"redirect_uri": "<insert redirect_uri>",
"scope": "payments",
"claims": {
"id_token": {
"openbanking_intent_id": {
"value": "<insert ConsentId>"
}
}
}
}

Create an authorisation URL with the following parameters. Make sure they are URL-encoded.

ParameterDescriptionRequired
response_typeAlways set to code id_token.yes
client_idThe client ID for your application.yes
redirect_uriOne of the redirect URIs that you defined when you created the application.yes
scopeThe scope that you are requesting, for example, accounts or payments. For file payments, you need the scope payments.yes
requestThe encoded JWT generated in the previous step.yes
response_modeIf set to fragment, parameters are passed in the fragment section of the redirect URI. Otherwise, they are passed in the URI query. Passing parameters in fragment is considered to be more secure.no
stateOAuth parameter that lets you restore the state of the application after redirection. If provided, this value is returned in the redirect URI.no

A sample authorisation URL looks like this:

https://oba.revolut.com/ui/index.html?response_type=code%20id_token&scope=payments&redirect_uri=<insert redirect URL>&client_id=<insert client_id>&request=<insert JWT from step 3.>&state=example_state
Expected result

Once you have redirected the user to the authorisation URL, they will need to provide their Revolut credentials and complete the payment authorisation.

After authorising the payment, the user will be redirected back to the redirect URL (redirect_uri) containing the authorisation code (code) as a URL parameter, as in the below example:

https://example.com/?code=oa_sand_sPoyVs-oMhyR36j5N-ZEVLfK9rQWPNssgIQqsOFZQ-c&id_token=<JWT id_token>&state=example_state

Use this authorisation code in the next step.

caution

The code is valid only for two minutes.

8. Exchange the authorisation code for an access token

Exchange the code parameter obtained when getting the consent for a new access token:

curl  --key private.key --cert transport.pem \
--location --request POST 'https://oba-auth.revolut.com/token' \
--header 'Content-Type:application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode'code=<insert code>'

Response

{
"access_token":"oa_prod_tP1Nofi1ixsRfBmVBtVPdIVN0J5x91imqmheQIWTS5s",
"token_type":"Bearer",
"expires_in":86376,
"id_token":"<JWT id_token>"
}
Expected result

The access token (access_token) returned in this response will allow you to execute the batch payment.

note

This access token is valid only for 24 hours.

9. Initiate the file payment

Now you can initiate the file payment on the user's behalf. Make a call to the /file-payments endpoint to initiate the payments.

In the request body, use the same JSON content which was used previously in the consent request, and add the Data.ConsentId key with the ConsentId value which you received when creating the consent.

note

For this request, you must also use:

curl --location --request POST 'https://oba.revolut.com/file-payments' \
--header 'x-fapi-financial-id: 001580000103UAvAAM' \
--header 'Content-Type: application/json' \
--header 'x-idempotency-key: 123' \
--header 'Authorization: Bearer <insert access_token from step 8.>' \
--header 'x-jws-signature: <insert JWS>' \
--data '{
"Data": {
"ConsentId": "f3e5d778-a0b6-48c5-bae2-886f0097d51f",
"Initiation": {
"FileType": "text/csv",
"FileHash": "2nDGfxr0OI5+ts/iz9/+mk3VYTxhamlWA3P65a5LuKs=",
"FileReference": "reference1234"
}
}
}

Response:

{
"Data": {
"ConsentId": "f3e5d778-a0b6-48c5-bae2-886f0097d51f",
"CreationDateTime": "2023-11-13T13:46:47.678627Z",
"FilePaymentId": "e82cced4-8277-4220-bb0a-72775876f2ea",
"Initiation": {
"DebtorAccount": {
"SchemeName": "UK.OBIE.IBAN",
"Identification": "GB95REVO00997053872360",
"Name": "John Doe"
},
"FileHash": "2nDGfxr0OI5+ts/iz9/+mk3VYTxhamlWA3P65a5LuKs=",
"FileReference": "reference1234",
"FileType": "text/csv"
},
"Status": "InitiationCompleted",
"StatusUpdateDateTime": "2023-11-13T13:46:47.678627Z"
},
"Links": {
"Self": "https://oba.revolut.com/file-payments/e82cced4-8277-4220-bb0a-72775876f2ea"
},
"Meta": {
"TotalPages": 1
}
}

For more details about this call:

See the API reference: Create a file payment

Congratulations!

You have successfully initiated your first file payment.

Save the FilePaymentId value from the response so that you can later check the status of the payments execution.

10. Check the file payment status

After you execute a file payment, it will typically go into the InitiationInProcess status.

To check the status of the batch payment, make a request and provide the file payment ID.

note

Request:

curl --location 'https://oba.revolut.com/file-payments/<FilePaymentId>' \
--header 'x-fapi-financial-id: 001580000103UAvAAM' \
--header 'Authorization: Bearer <access_token>'

Response:

{
"Data": {
"Status": "InitiationCompleted",
"StatusUpdateDateTime": "2023-11-13T13:46:49.116202Z",
"CreationDateTime": "2023-11-13T13:46:47.678627Z",
"FilePaymentId": "e82cced4-8277-4220-bb0a-72775876f2ea",
"ConsentId": "f3e5d778-a0b6-48c5-bae2-886f0097d51f",
"Initiation": {
"DebtorAccount": {
"SchemeName": "UK.OBIE.IBAN",
"Identification": "GB95REVO00997053872360",
"Name": "John Doe"
},
"FileType": "text/csv",
"FileHash": "2nDGfxr0OI5+ts/iz9/+mk3VYTxhamlWA3P65a5LuKs=",
"FileReference": "reference1234"
}
},
"Links": {
"Self": "https://oba.revolut.com/file-payments/e82cced4-8277-4220-bb0a-72775876f2ea"
},
"Meta": {
"TotalPages": 1
}
}

For more details about this call:

See the API reference: Retrieve a file payment

11. Check the status of all payments

You can also check the status of all the payments included in the file payment.

note

Request:

curl --location 'https://oba.revolut.com/file-payments/<FilePaymentId>/report-file' \
--header 'x-fapi-financial-id: 001580000103UAvAAM' \
--header 'Authorization: Bearer <access_token>'

Response:

{
"Payments": [
{
"Amount": {
"Amount": "10.00",
"Currency": "GBP"
},
"Reference": "First comment",
"Status": "Created"
},
{
"Amount": {
"Amount": "10.00",
"Currency": "GBP"
},
"Reference": "Second comment",
"Status": "Created"
}
]
}

For more details about this call:

See the API reference: Retrieve all payments of a file payment

What's next

Was this page helpful?