NAV Navbar
shell

TransferWise for Banks API

Welcome to the TransferWise for Banks API documentation.

Base URL Sandbox

https://api.sandbox.transferwise.tech

Base URL LIVE

https://api.transferwise.com

What is it?

Building a bank integration with TransferWise allows a bank to offer TransferWise transfers directly to their users through their online banking or mobile apps.

What are the benefits for my bank?

How does it work?

See what some of our bank partners have to say


Example: the N26 native user experience using TransferWise API

alt text

Please contact banks@transferwise.com to get started.

Bank Integrations Guide

This guide describes in detail the technical implementation of a TransferWise integration for a bank. If you need any help please reach out to the TransferWise team here.

API access

TransferWise uses standard OAuth 2.0 protocol for authentication and authorization.

Once our partnership begins, we’ll send you API access credentials for the sandbox environment consisting of a Client ID and a Client Secret. The credentials are needed to complete the authorization_code grant type of OAuth 2.0 through which the customer will allow your application to be able to act on their behalf. We also need redirect_url from your technical team so that we can limit our callbacks to only that URL, this is URL that we will forward users to after successfully granting your application access to their TransferWise account. Specifying this explicitly makes the integration more secure. This article about OAuth 2.0 framework is a great way to refresh your knowledge about the protocol itself.

SANDBOX and LIVE environments

Customized user interface

You will build your TransferWise user experience directly into your mobile and desktop applications.

There are different ways to build the frontend experience, especially when it comes to the sequence of steps in the payment flow. This guide is more like a list of building blocks and ideas for what you can do, rather than a strict step-by-step guide.

For example, you can put sign up/log in step as a first step, then show the currency calculator, and then collect recipient details. Alternatively, you can build it so a user starts from the calculator, then you collect recipient details, and as a last step ask user to sign up/log in.

We have plenty of examples to show you how this has been done by our current partners and can help you to build a great experience for your customers.

Building your backend

You should expose an API internally for your web and mobile clients to call to provide the required TransferWise features. Your backend system will manage both communication to the TransferWise API and internal operations such as checking a user has sufficient balance to make the requested transfer and triggering the funds to be sent to TransferWise when they confirm a transfer.

You should also store a copy of certain data relating to TransferWise to decrease latency and increase resiliency when users review previous transfers they made or recipients they sent funds to. The extent of what you store will depend on your integration.

You should also build a polling mechanism to periodically update the status of a transfer and its delivery estimate, keeping your user up to date of where their transfer is in the process.

We have a dedicated team focusing on bank partnerships who will help you along the way, sharing knowledge and experience from previous integrations to help you build a robust and highly available system.

Your TransferWise user experience

User onboarding flow

The user onboarding flow consists of these building blocks.
You need to go through this flow only once for each customer before they can set up their first transfer.

Transfer flow

To create transfers on behalf of users you need these building blocks:

Transfer update polling

To keep your users informed of the status and estimated time of arrival of their transfer:

Get user authorization for existing accounts

At a high level there are three steps to gaining access to an existing TransferWise account.

  1. Your app redirects the user to TransferWise authorization web page, which prompts them to login if necessary.
  2. The user logs in to TransferWise.
  3. The user agrees to provide access, the TransferWise authorization page then redirects user back to your pre-configured url, including a code you can use to generate user tokens. e.g.

    https://www.yourbank.com/?code=[CODE]

These steps are explained in more detail below.

1. Your banking app redirects user to TransferWise authorization web page

Your website or app opens the following url in the user's browser.

Sandbox:
https://sandbox.transferwise.tech/oauth/authorize/?client_id={clientId}&redirect_uri={redirectUri}
Live:
https://api.transferwise.com/oauth/authorize/?client_id={clientId}&redirect_uri={redirectUri}

List of available parameters:

Parameter Description
client_id (required) The client ID you received from us.
redirect_uri (required) The preconfigured URL in your application where users will be sent after authorization.
state An opaque value, used for security purposes. If this parameter is set in the request, then it is returned to the application as part of the redirect_uri. More about state parameter.

On mobiles apps you should not use WebView components to show the authorization page to the users because they are not secure and will not allow users to log in to TransferWise with Google, which is an option used by some of our users. Your app should instead open the device's full browser app.

Please also note that provided [CODE] expires within 30 minutes and is one time use only.

2. The user logs in to TransferWise

Our usual log in screens are presented to the user if they are not already logged in on the browser being used. If enabled for a user they will also be prompted to go through our two-factor authentication procedure.

3. The user agrees to grant access and we forward them to your redirect_url

Once a user gives your banking app authorization to connect to TransferWise and access their data, the user is redirected back to your redirect_url with a generated code query string value. For example

https://www.yourbank.com/?code=[CODE]

Your website or service can then use this code to obtain the access token to act on behalf of the user account described in the get user tokens section.

If you are building your TransferWise integration as a native mobile phone app then the redirect URL should be able to handle returning the user to the correct place in the app.

At the point you gain access to a user account, you should double check if it is the one you were expecting to be given access to - sometimes users can get confused and log in to a different account. Together we want to avoid TransferWise accounts being linked to bank accounts of a different person or business, therefore you should check the user's details once the link is created. Currently you should do this sanity check based on the date of birth of the user but we are working on a more robust solution. If the DoB exists but doesn't match then you should not allow the link to be made and inform the user we do not think the accounts match and to get in touch with customer service.

Sign up new users via API

If the user doesn't already have a TransferWise account then you can create one for them. The signup with registration code feature lets you create new users directly via an API call, without the need to redirect new users to the TransferWise authorization page. This way new users can complete everything without ever leaving your banking app, making a very streamlined flow.

We can provide this option to banks where we can create a trusted reliance model on your KYC processes. Please discuss this option with the team supporting your integration.

Existing TransferWise users will always need to be redirected to authorization page flow, you can detect this at the point you attempt to create the user based on the API response.

Note that these new users have to accept TransferWise Terms and Conditions as part of their sign up process nevertheless. See endpoint Terms and conditions.

Get user tokens

If using the first option to get user authorization for existing accounts, then this step is to generate user-level tokens so you can call API endpoints on behalf of the user who authorized your banking app. You do this using the access code that was returned to you as a query string parameter in the redirect_uri you provided us.

Example Request:

curl \
-u '[your-api-client-id]:[your-api-client-secret]' \
-d 'grant_type=authorization_code' \
-d 'client_id=[your-api-client-id]' \
-d 'code=[code-from-redirect-uri]' \
-d 'redirect_uri=https://www.yourbank.com' \
'https://api.sandbox.transferwise.tech/oauth/token' 

You will be returned an access token and a refresh token.

Example Response:

  {
    "access_token":"ba8k9935-62f2-475a-60d8-6g45377b4062",
    "token_type":"bearer",
    "refresh_token":"a235uu9c-9azu-4o28-a1kn-e15500o151cx",
    "expires_in": 43199,
    "scope":"transfers"
  }

For calling API endpoints you need to provide the user's access_token in the request's HTTP header in the format Authorization: Bearer <access_token>. Access tokens are short lived for security reasons, they are only valid for 12 hours by default. When they expire you need to use the refresh_token to generate a new access_token.

This means you have to securely store the user's refresh_token in order to generate a new access_token each time they use your TransferWise integration.

Request

POST https://api.sandbox.transferwise.tech/v1/oauth/token

Use Basic Authentication with your api-client-id/api-client-secret as username/pwd.

Field Description Format
grant_type "authorization_code" Text
client_id your api_client_id Text
code Code provided to you upon redirect back from authorization flow. See step Get user authorization. Text
redirect_uri Redirect page associated with your api client credentials Text

Response

Field Description Format
access_token Access token to be used when calling API endpoints on behalf of user. Valid for 12 hours. uuid
token_type "bearer" Text
refresh_token Refresh token which you need to use in order to request new access_token. The lifetime of refresh tokens is 10 years. uuid
expires_in Expiry time in seconds Integer
scope "transfers" Text

Refresh user access token

Example Request:

      curl \
      'https://api.sandbox.transferwise.tech/oauth/token' \
      -u '[your-api-client-id]:[your-api-client-secret]' \
      -d 'grant_type=refresh_token' \
      -d 'refresh_token=[user's refresh token]'

Example Response:

  {
    "access_token":"be69d566-971e-4e15-9648-85a486195863",
    "token_type":"bearer",
    "refresh_token":"1d0ec7b9-b569-426d-a18d-8dead5b6a3cc",
    "expires_in":43199,
    "scope":"transfers"
  }

Access tokens are valid for 12 hours, so upon expiry you need to use refresh_token to generate new access_token.

In order to maintain an uninterrupted connection, you can request a new access token whenever it’s close to expiring. There is no need to wait for the actual expiration to happen first.

Request

POST https://api.sandbox.transferwise.tech/v1/oauth/token

Use Basic Authentication with your api-client-id/api-client-secret as username/pwd.

Field Description Format
grant_type "refresh_token" Text
refresh_token User's refresh_token obtained in Get user tokens step. uuid

Response

Field Description Format
access_token Access token to be used when calling API endpoints on behalf of user. Valid for 12 hours. uuid
token_type "bearer" Text
refresh_token Refresh token which you need to use in order to request new access_token once the existing one expires uuid
expires_in Expiry time in seconds Integer
scope "transfers" Text

Token Expiry

It is possible that a user's refresh token will become invalid. This could happen for a number of reasons, for example:

Due to this possibility your application should handle a failing refresh token scenario - to do this depends on how you originally gained access to the user.

1. An existing user granted your application access to the account

If you were granted access by an existing user then you should send the user through the same flow as you initially did to generate tokens described in get user authorization for existing accounts.

2. Your application created the user

In the case you created the user using the sign up new users via API flow then the mechanism for regenerating tokens is dependent on whether the user you created has "reclaimed" their TransferWise account and used our website or apps directly.

If the user has not reclaimed their account then the original registration_code you generated should still be able to generate new tokens for the user. Because of this you should store this code alongside the created user ID in your database at the point of user generation.

If the previously stored token fails with an error code 400 and error:

{
  "error": "invalid_grant",
  "error_description": "Invalid user credentials."
}

In this case you can assume the user has reclaimed the account and push them through the get user authorization for existing accounts flow.

This flowchart describes the different scenarios you will encounter and how you should handle them. User onboarding flow chart

Create personal user profile

When you first get access to a user's TransferWise user account you cannot predict if they already have submitted their profile data or not.

The User Profiles.List endpoint will give you data for both personal and business profiles, if they exist. This makes it easy to figure out if a user has already set up this data with TransferWise or not. If the user already has a personal profile set up, then you can skip this creation step.

If you are using the sign up new users via API feature then you absolutely need to create a personal profile for the user, however it is possible you will also need to do it when getting access to an existing user account should we have incomplete data.

There are several steps to creating a new personal user profile:

1) Create personal user profile – general data. This includes customer name, date of birth, and phone number.

2) Create personal user profile – upload verification ID data. If required for your integration (dependent on jurisdiction) then send ID document information for your user. The TransferWise integration team will work on this with you to decide if it is required.

3) Open update window. Open the update window for the profile updates.

4) Create personal user profile – address data. Add address information to the personal user profile.

5) Close update window. Close the update window for the profile updates.

Create business user profile

A personal profile has to be created first. You can’t create a business user profile without a personal profile.

Creating a business profile is similar to how you created a personal profile. There are four steps:

1) Create business user profile – general data. This includes business name, type and other information.

2) Open update window. Open the update window for the profile updates.

3) Create business user profile – address data. Add address information to the business user profile.

4) Create business user profile - director data. Add business director information to the business user profile.

5) Create business user profile - UBO data. Add ultimate business owner information to the business user profile.

6) Close update window. Close the update window for the profile updates.

Profile extensions

Some regions demand more profile data due to local regulations, in order to be compliant the extra data has to be provided. This is required based on jurisdiction of operation and customer demographics of your bank or other financial institution, please discuss with the TransferWise for Banks team to see if it is necessary to include. To collect this data please use our User Profile Extensions dynamic form.

Create quote

Please look at Create quote under Full API Reference.

You must include the profile ID when creating the quote using the profile parameter.

Create or select recipient account

Please look at Create recipient account under Full API Reference for information on the calls to create recipients.

It is also recommended that you use the GET accounts endpoint to load the user's previously used recipients and allow them to select from them in your user interface. This allows them to only have to create a recipient once and then re-use it in future, plus it allows existing TransferWise users to use their familiar recipients from our platform.

You should store a cached copy of the recipients that are used by users of your app such that you can load that data again quickly to show in your UI, for example a transfer tracking screen might show recipient data. You could either store the entire data or just the name and accountSummary.

Please note, when creating a new transfer always reload the full list of recipients over our API rather than use the ones you have saved because you cannot be certain the recipients that you store a copy of have not been deleted on TransferWise in the meantime.

Update quote with selected recipient

Now that a recipient has been selected you need to update the quote with that recipient in order for us to calculate if the price has changed based on that selection. For example the fees and delivery estimate are different in the case of sending USD to a country other than the USA - we call this Global USD.

You need to do this in order to show the customer the correct final price and delivery estimate time before they commit to creating and funding the transfer.

Please look at Update quote under the full API Reference to learn how to do this.

Create transfer

Please look at Create transfer under the full API Reference for information on creating a transfer using your quote and recipient.

Fund transfer

Once you have successfully created a transfer via the TransferWise API you should debit the exact source amount from your customer's bank account and send the funds to TransferWise’s local bank account via domestic payment. You should send the amount provided in the final quote object after any recipient updates for global currencies. The details of this bank account will be shared with you by the TransferWise team helping your integration.

In order for us to link this incoming domestic payment with a corresponding transfer order, we need you to use specific text in the "payment reference" field. Get the transfer id for the transfer you're trying to fund and append the letter T as a prefix. So for a hypothetical transfer with id 80106743, the correct "payment reference" would be T80106743.

Alternatively, we offer a "prefunded" model to some banks who want to speed up transfers for their customers in regions where the domestic payment networks are slow. If you are interested in this model please get in touch with the TransferWise team to discuss the option and for technical documentation on how it works.

Track transfer status

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v1/transfers/{transferId} \
     -H "Authorization: Bearer <your api token>" 

Example Response:

{
    "id": 468956,
    "user": <your user id>,
    "targetAccount": <recipient account id>,
    "sourceAccount": null,
    "quote": <quote id>,
    "status": "outgoing_payment_sent",
    "reference": "to my friend",
    "rate": 0.9065,
    "created": "2018-08-28 07:43:55",
    "business": <your business profile id>,
    "transferRequest": null,
    "details": {
        "reference": "to my friend"
    },
    "hasActiveIssues": false,
    "sourceCurrency": "EUR",
    "sourceValue": 661.89,
    "targetCurrency": "GBP",
    "targetValue": 600,
    "customerTransactionId": "bd244a95-dcf8-4c31-aac8-bf5e2f3e54c0"
}

You can check your latest transfer status by polling this endpoint. Normal state flow of transfers is as follows:

Incoming Payment Waiting ⇒ Processing ⇒ Funds Converted ⇒ Outgoing Payment Sent

Outgoing Payment Sent is the final state of the normal flow. If the payment fails, the problematic flow will continue. An example would be if the recipient bank account doesn’t exist or is entered wrong and the payment is returned. The problematic state flow of transfers is:

Outgoing Payment Sent ⇒ Bounced Back ⇒ Funds Refunded

Most bounce backs occur within 2-3 business days. However, to be on the safe side, we advise you to poll the transfer status for potential bounce backs for two weeks after the payment is sent.


Transfer state flow

alt text

See below for the full list of transfer statuses and what they mean in the order of occurrence:

Keep in mind the transfer statuses in our API have different names than what you’ll see on our website or app. That’s because we use more consumer friendly language in the front end of our products. For example "Completed" on our website means outgoing_payment_sent in the API.

You should use the following descriptions in your website or app for the potential statuses we return:

Status Description
incoming_payment_waiting "On its way to TransferWise"
incoming_payment_initiated "On its way to TransferWise"
processing "Processing"
funds_converted "Processing"
outgoing_payment_sent "Sent"
charged_back "Charged back"
cancelled "Cancelled"
cancelled_refund_processing "Refund in progress"
funds_refunded "Refunded"
bounced_back "Bounced back"
unknown "Unknown"



Sandbox limitations

We don't send out email notifications about payment status changes in sandbox.

We don't process payments in sandbox, which means that created payments remain in their first state. You can use Simulation endpoints to change transfer statuses in sandbox.

Get updated transfer delivery time

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v1/delivery-estimates/{transferId} \
     -H "Authorization: Bearer <your api token>" 

Example Response:

{
   "estimatedDeliveryDate" : "2018-01-10T12:15:00.000+0000"
}

Get the live delivery estimate for a transfer by the transfer ID. The delivery estimate is the time at which we currently expect the transfer to arrive in the beneficiary's bank account. This is not a guaranteed time, but we’re working hard to make these estimates as accurate as possible.

Request

GET https://api.sandbox.transferwise.tech/v1/delivery-estimates/{transferId}

Response

You need to save the transfer id to track its status later.

Field Description Format
estimatedDeliveryDate Estimated time when funds will arrive to recipient's bank account Timestamp

Updating personal profile

When user data changes the personal profile information must be updated.

1) Open update window. Open the update window for profile updates.

2) Update personal profile - general data. Update the personal profile data.

3) Close update window. Close the update window for profile updates.

Updating business profile

When business data changes the business profile information must be updated.

1) Open update window. Open the update window for profile updates.

2) Update business profile - general data. Update the business profile data.

3) Update business profile - directors data. Update directors information in the business user profile.

3) Update business profile - UBO data. Update ultimate business owners information in the business user profile.

4) Close update window. Close the update window for profile updates.

Edge case handling

This section discusses some edge cases that you should test and handle before going live with your integration.

Email address considerations

Due to how getting access to user accounts works the TransferWise platform relies on user email addresses matching between the bank and ourselves. At the point the bank attempts to create a user we check and see if an account already exists for that email address, if so we return a 409 response and the client application forwards the user to login to TransferWise to do the OAuth grant flow.

This works well when the email addresses match in the first place and aren't updated on either side after the link is established. Of course, this is not always going to be the case so we must consider what happens in either eventuality.

Non-matching email addresses

If a user already has a TransferWise account and you create a user for the same person under a different email address they could end up with a duplicate user account under the second email address. Currently we monitor this behaviour for abuse but we are working on a more robust user creation solution to prevent this from occurring.

Email Change

It is possible to change a user’s email address both at TransferWise and potentially also on the bank platform. These flows can cause complications with the integration.

Email changed at TransferWise

If a user changes their email address, all tokens to the user account are revoked. In this case the bank will receive a 400 when attempting to generate an access_token and as such should follow the same process as described in the token expiry section above and start the sign up flow from the beginning.

In this case, if the user has changed their email address at TransferWise, it is possible the user will end up with a new TransferWise account using their old email address still held by the bank, or they might link their bank account to a different already existing TransferWise account under the old email address.

Email changed at the bank

In this case the tokens will remain valid for the TransferWise account, however, depending on how the user originally linked the account, different things can happen when/if that token expires.

If the bank created the account originally, they will be unable to generate tokens using the registration_code they have, as the endpoint requires the email address which will now no longer match. To mitigate this it is recommended that the bank store the email that was originally used for signup alongside the registration code and use this rather than the most up to date email address they store for the user.

If the token expires for a user not created by the bank and the user has a new email address at the bank then they can be pushed through the signup flow with this new email address and either have a new account created or link an existing against the new email, as described in token expiry.

The result of many of these flows is that the user may end up with more than one TransferWise account, which is undesirable. Currently we monitor this behaviour for abuse but we are working on a more robust user creation scenario to prevent this from occurring.

Email change mitigation

The result of these eventualities are that over time a user of the bank could be linked to more than one TransferWise account and so therefore you will need to be defensive when requesting older user data as the request may fail because we forbid one user to access other user's data. We recommend to keep a local copy of your user's transfer data and update it asynchronously such that older transfers remain accessible to the user in the case where it can no longer be accessed. You should also make sure to handle these failing calls gracefully and continue to process transfers that can be accessed over the API.

In the event a user is not happy at losing access to their older data or having two accounts is confusing then we can manually update the email addresses to match for the two accounts they want.

Going live checklist

1. Make your integration bulletproof

2. Set up security for LIVE environment

3. Do some testing in LIVE

4. Signup for API status notifications.

Global Currencies

Global Currencies is a TransferWise product that allows customers to send currencies to countries other than the one they are domestic to. For example, sending US dollars to somebody in Hong Kong, rather than the USA.

It is quite common, especially for businesses, to operate in USD, GBP or EUR despite being based outside of the respective country of these currencies. In some countries, these bank accounts do not use the standard account details that a domestic account would, for example an account number and sort code in UK. Instead, these accounts are more likely to be addressed using an IBAN.

The TransferWise API supports this product in version two of the quotes API. The key difference this API provides against version one is the ability to update a quote with a recipient before a transfer is created, using the update quote endpoint. If you set the ID of a recipient that represents an account of, for example, a USD recipient with an IBAN (i.e. an account with "type": "swiftref") then the returned quote will be updated to represent we will not be sending these funds domestically in the USA and as such charge different fees.

Creating a global currency transfer

The process is as follows:

  1. Create a quote for the currencies you wish to send between, e.g. GBP to USD.

  2. Create a swiftref recipient for using the create account endpoint, based on the requirements set out in account requirements.

  3. Update the quote created in step 1 with the ID of the recipient created in step two.

  4. You will now see the payOut of the quote to have updated to be of type SWIFT, and the paymentOptions array to have all options updated to also have a payOut of type SWIFT and different fees. In this case you should show the user the fees to pay using the option that has a pay in type of BANK_TRANSFER and pay out of SWIFT, unless you are using a non-standard pay in method such as bulk settlement.

Contact Us

Having issues while calling our API endpoints?
Check our API status at https://status.transferwise.com/ If you would like to receive status change notifications, feel free to signup here.

Have a technical question about API?
Send email to api@transferwise.com

Have a question about how TransferWise works?
Search TransferWise Help Centre. https://transferwise.com/help

Talk to the bank integrations team
Please get in touch with our team at banks@transferwise.com

Full API Reference

Users

Get By Id

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v1/users/{userId} \
     -H "Authorization: Bearer <your api token>" 

Example Response:

{
  "id": 101,
  "name": "Example Person",
  "email": "person@example.com",
  "active": true,
  "details": {
    "firstName": "Example",
    "lastName": "Person",
    "phoneNumber": "+37111111111",
    "occupation": "",
    "address": {
      "city": "Tallinn",
      "countryCode": "EE",
      "postCode": "11111",
      "state": "",
      "firstLine": "Road 123"
    },
    "dateOfBirth": "1977-01-01",
    "avatar": "https://lh6.googleusercontent.com/photo.jpg",
    "primaryAddress": 111
  }
}

Get authenticated user details by user id. Response includes also personal user profile info.

Request

GET https://api.sandbox.transferwise.tech/v1/users/{userId}

Response

Field Description Format
id userId Integer
name User full name Text
email User email Text
active If user is active or not Boolean
details.firstName User first name Text
details.lastName User lastname Text
details.phoneNumber Phone number Text
details.dateOfBirth Date of birth YYYY-MM-DD
details.occupation Person occupation Text
details.avatar Link to person avatar image Text
details.primaryAddress Address object id to use in addesses endpoints Integer
details.address.countryCode Address country code in 2 digits. "US" for example Text
details.address.firstLine Address first line Text
details.address.postCode Address post code Text
details.address.city Address city name Text
details.address.state Address state code State code. Required if country is US, CA, AU, BR. Text
details.address.occupation User occupation. Required for US, CA, JP Text

Get the currently logged in user

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v1/me \
     -H "Authorization: Bearer <your api token>" 

Example Response:

{
  "id": 101,
  "name": "Example Person",
  "email": "person@example.com",
  "active": true,
  "details": {
    "firstName": "Example",
    "lastName": "Person",
    "phoneNumber": "+37111111111",
    "occupation": "",
    "address": {
      "city": "Tallinn",
      "countryCode": "EE",
      "postCode": "11111",
      "state": "",
      "firstLine": "Road 123"
    },
    "dateOfBirth": "1977-01-01",
    "avatar": "https://lh6.googleusercontent.com/photo.jpg",
    "primaryAddress": 111
  }
}

Get authenticated user details for the user's token submitted in the Authorization header. Response includes also personal user profile info.

Request

GET https://api.sandbox.transferwise.tech/v1/me

Response

Field Description Format
id userId Integer
name User full name Text
email User email Text
active If user is active or not Boolean
details.firstName User first name Text
details.lastName User lastname Text
details.phoneNumber Phone number Text
details.dateOfBirth Date of birth YYYY-MM-DD
details.occupation Person occupation Text
details.avatar Link to person avatar image Text
details.primaryAddress Address object id to use in addesses endpoints Integer
details.address.countryCode Address country code in 2 digits. "US" for example Text
details.address.firstLine Address first line Text
details.address.postCode Address post code Text
details.address.city Address city name Text
details.address.state Address state code State code. Required if country is US, CA, AU, BR. Text
details.address.occupation User occupation. Required for US, CA, JP Text

Sign Up with Registration Code

1) Example Request: Get Client Credentials Token

curl -X "POST" "https://api.sandbox.transferwise.tech/oauth/token" \
     -H 'Content-Type: application/x-www-form-urlencoded' \
     -u '[your-api-client-id]:[your-api-client-secret]' \
     --data-urlencode "grant_type=client_credentials" 

1) Example Response: Get Client Credentials Token

  {
    "access_token":"ba8k1234-00f2-475a-60d8-6g45377b4062",
    "token_type":"bearer",
    "expires_in": 43199,
    "scope":"transfers"
  }

















2) Example Request: Create User

curl -X POST https://api.sandbox.transferwise.tech/v1/user/signup/registration_code \
     -H "Authorization: Bearer <your client credentials token>" \
     -H "Content-Type: application/json" \
     -d '{ 
          "email": <user email>,
          "registrationCode": <registration code>
        }'

2) Example Response: Create User (Success (200) user created successfully)

      {
        "id": 12345,
        "name": null,
        "email": "new.user@domain.com",
        "active": true,
        "details": null
      }

2) Example Response: Create User (Failure (409): User already exists)

      {
        "errors": [
          {
            "code": "NOT_UNIQUE",
            "message": "You’re already a member. Please login",
            "path": "email",
            "arguments": [
              "email",
              "class com.transferwise.fx.api.ApiRegisterCommand",
              "existing.user@domain.com"
            ]
          }
        ]
      }








3) Example Request: Get User Tokens

curl \
-u '[your-api-client-id]:[your-api-client-secret]' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=registration_code' \
-d 'email=<user email>' \
-d 'client_id=[your-api-client-id]' \
-d 'registration_code=<registration code used to create user>' \
'https://api.sandbox.transferwise.tech/oauth/token' 

3) Example Response: Get User Tokens (Success: 200)

    {
      "access_token": "01234567-89ab-cdef-0123-456789abcdef",
      "token_type": "bearer",
      "refresh_token": "01234567-89ab-cdef-0123-456789abcdef",
      "expires_in": 43199,
      "scope": "transfers"
    }

3) Example Response: Get User Tokens (Failure: 401 - User reclaimed the account or invalid registration code used)

    {
      "error": "invalid_grant",
      "error_description": "Invalid user credentials."
    }

It enables onboarding new users to TransferWise via backend API calls only. To get authorization from existing TransferWise users, you still need to redirect them to our authorization webpage.

There are 3 steps you need to go through:

1) Get Client Credentials Token

Obtain access_token based on your API client credentials.

Request

POST https://api.sandbox.transferwise.tech/oauth/token

Use Basic Authentication with your api-client-id/api-client-secret as username/pwd and also use the header Content-Type: application/x-www-form-urlencoded.

Field Description Format
grant_type "client_credentials" Text

Response

Field Description Format
access_token Access token to be used when calling "create user" endpoint. Valid for 12 hours. uuid
token_type "bearer" Text
expires_in Expiry time in seconds Integer
scope "transfers" Text

2) Create User

TransferWise uses email address as unique identifier for users. If email is new (there is no active user already) then new user will be created.

When you are submitting an email which already exists amongst our users then you will get HTTP 409 response with a message that says "You’re already a member. Please login". If user already exists, then you need to redirect to Get user authorization webpage.

Request

POST https://api.sandbox.transferwise.tech/v1/user/signup/registration_code

Use access_token obtained in first step as authentication header.

Field Description Format
email New user's email address Email
registrationCode Randomly generated registration code that is unique to this user. At least 32 characters long.
You need to store registration code to obtain access token on behalf of this
newly created user in next step.
Please apply the same security standards to handling registration code as if it was a password.
Text, min length is 32 chars

Response

Field Description Format
id userId Integer
name User full name. Empty. Text
email Customer email Text
active true Boolean
details User details. Empty. Group

3) Get User Tokens

You can now use registration code to obtain user access token and refresh token. This step can be repeated as long as user does not reclaim their TransferWise account. If user has reclaimed the account, then redirect to Get user authorization flow should be used instead.

Refresh user access token works same way for this flow as well.

Request

POST https://api.sandbox.transferwise.tech/oauth/token

Use Basic Authentication with your api-client-id/api-client-secret as username/pwd.

Field Description Format
grant_type "registration_code" Text
email New user's email address Email
client_id Your api_client_id Text
registration_code registrationCode from step 2 Text

Response

Field Description Format
access_token Access token to be used when calling API endpoints on behalf of user. Valid for 12 hours. uuid
token_type "bearer" Text
refresh_token Refresh token which you need to use in order to request new access_token. The lifetime of refresh tokens is 10 years. uuid
expires_in Expiry time in seconds Integer
scope "transfers" Text

User Profiles

Create (Personal)

Example Request:

curl -X POST https://api.sandbox.transferwise.tech/v1/profiles \
     -H "Authorization: Bearer <your api token>" \
     -H "Content-Type: application/json" \
     -d '{ 
          "type": "personal",
          "details": {
            "firstName": "Oliver",
            "lastName": "Wilson",
            "dateOfBirth": "1977-07-01",
            "phoneNumber": "+3725064992"
           }
        }'

Example Response (Personal):

{
  "id": <your personal profile id>,
  "type": "personal",
  "details": {
    "firstName": "Oliver",
    "lastName": "Wilson",
    "dateOfBirth": "1977-07-01",
    "phoneNumber": "+3725064992",
    "avatar": "",
    "occupation": "",
    "primaryAddress": null
  }
}

Create personal user profile. Same person cannot have multiple active duplicate user profiles. Thus creating multiple profiles with the same details will fail. Use the access_token you received to act on behalf of the user in the Authorization header.

Request

POST https://api.sandbox.transferwise.tech/v1/profiles

Field Description Format
type "personal" Text
details.firstName First name Text
details.lastName Last name Text
details.dateOfBirth Date of birth YYYY-MM-DD
details.phoneNumber
(optional)
Phone number Text

Response

Field Description Format
id profileId Integer
type "personal" Text
details.firstName First name Text
details.lastName Last name Text
details.dateOfBirth Date of birth YYYY-MM-DD
details.phoneNumber Phone number Text
details.avatar Link to person avatar image Text
details.occupation Person occupation Text
details.primaryAddress Address object id Integer

Create (Business)

Example Request:

curl -X POST https://api.sandbox.transferwise.tech/v1/profiles \
     -H "Authorization: Bearer <your api token>" \
     -H "Content-Type: application/json" \
     -d '{ 
          "type": "business",
          "details": {
            "name": "ABC Logistics Ltd",
            "registrationNumber": "12144939",
            "acn": null,
            "abn": null,
            "arbn": null,
            "companyType": "LIMITED",
            "companyRole": "OWNER",
            "webpage": "https://abc-logistics.com",
            "businessCategory":"CONSULTING_IT_BUSINESS_SERVICES",
            "businessSubCategory":"DESIGN"
           }
        }'

Example Response (Business):

{
  "id": <your business profile id>,
  "type": "business",
  "details": {
     "name": "ABC Logistics Ltd",
     "registrationNumber": "12144939",
     "acn": null,
     "abn": null,
     "arbn": null,
     "companyType": "LIMITED",
     "companyRole": "OWNER",
     "descriptionOfBusiness": "Information and communication",
     "webpage": "https://abc-logistics.com",
     "primaryAddress": null
   }
}

Create business user profile. You would need to create personal profile first always. Business profile cannot be created without personal profile.

Request (Business)

POST https://api.sandbox.transferwise.tech/v1/profiles

Field Description Format
type "business" Text
details.name Business name Text
details.registrationNumber Business registration number Text
details.acn Australian Company Number (only for AUS businesses) Text
details.abn Australian Business Nnumber (only for AUS businesses) Text
details.arbn Australian Registered Body Number (only for AUS businesses) Text
details.companyType Company legal form. Allowed values:
  • LIMITED
  • PARTNERSHIP
  • SOLE_TRADER
  • LIMITED_BY_GUARANTEE
  • LIMITED_LIABILITY_COMPANY
  • FOR_PROFIT_CORPORATION
  • NON_PROFIT_CORPORATION
  • LIMITED_PARTNERSHIP
  • LIMITED_LIABILITY_PARTNERSHIP
  • GENERAL_PARTNERSHIP
  • SOLE_PROPRIETORSHIP
  • PRIVATE_LIMITED_COMPANY
  • PUBLIC_LIMITED_COMPANY
  • TRUST
  • OTHER
Text
details.companyRole Role of person. Allowed Values:
  • OWNER
  • DIRECTOR
  • OTHER
Text
details.descriptionOfBusiness Sector / filed of activity Text
details.webpage Business webpage Text
details.businessCategory Type of business, see below for permitted values Text
details.businessSubCategory Specifc sub category of the business type, see below for permitted values Text

Business Category

Ensure when submitting a business profile that you submit a category and associated sub-category from the list below. You should map from the information you have about the business to one of our categories and sub-categories. If this is problematic please get in touch with the TransferWise for Banks team to discuss alternate solutions.

The categories and their sub-categories are as follows:

Response (Business)

Field Description Format
id profileId Integer
type "business" Text
details.name Business name Text
details.registrationNumber Business registration number Text
details.acn Australian Company Number (only for AUS businesses) Text
details.abn Australian Business Nnumber (only for AUS businesses) Text
details.arbn Australian Registered Body Number (only for AUS businesses) Text
details.companyType Company legal form Text
details.companyRole Role of person Text
details.webpage Business webpage Text
details.primaryAddress Address object id Integer
details.businessCategory Type of business Text
details.businessSubCategory Specifc sub category of the business type Text

Update

Example Request:

curl -X PUT https://api.sandbox.transferwise.tech/v1/profiles \
     -H "Authorization: Bearer <your api token>" \
     -H "Content-Type: application/json" \
     -d '{ 
          "type": "personal",
          "details": {
            "firstName": "Oliver",
            "lastName": "Wilson",
            "dateOfBirth": "1977-07-01",
            "phoneNumber": "+3725064992"
           }
        }'

Example Response:

{
  "id": <your personal profile id>,
  "type": "personal",
  "details": {
    "firstName": "Oliver",
    "lastName": "Wilson",
    "dateOfBirth": "1977-07-01",
    "phoneNumber": "+3725064992",
    "avatar": "",
    "occupation": "",
    "primaryAddress": null
  }
}

Update user profile information. If user profile has been verified by TransferWise then there are restrictions on what information is allowed to change.

Request

PUT https://api.sandbox.transferwise.tech/v1/profiles

Request and response is same as described in Create (Personal) and Create (Business)

Get By Id

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v1/profiles/{profileId} \
     -H "Authorization: Bearer <your api token>" 

Example Response:

{
  "id": <your personal profile id>,
  "type": "personal",
  "details": {
    "firstName": "Oliver",
    "lastName": "Wilson",
    "dateOfBirth": "1977-07-01",
    "phoneNumber": "+3725064992",
    "avatar": "",
    "occupation": "",
    "primaryAddress": null
  }
}

Get profile info by id.

Request

GET https://api.sandbox.transferwise.tech/v1/profiles/{profileId}

List

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v1/profiles \
     -H "Authorization: Bearer <your api token>" 

Example Response:

[
    {
      "id": <your personal profile id>,
      "type": "personal",
      "details": {
        "firstName": "Oliver",
        "lastName": "Wilson",
        "dateOfBirth": "1977-07-01",
        "phoneNumber": "+3725064992",
        "avatar": "",
        "occupation": "",
        "primaryAddress": null
      }
    },
    {
      "id": <your business profile id>,
      "type": "business",
      "details": {
        "name": "ABC Logistics Ltd",
        "registrationNumber": "12144939",
        "acn": null,
        "abn": null,
        "arbn": null,
        "companyType": "LIMITED",
        "companyRole": "OWNER",
        "descriptionOfBusiness": "CHARITY_AND_NOT_FOR_PROFIT",
        "webpage": "https://abc-logistics.com",
        "primaryAddress": null,
        "businessCategory": "CHARITY_AND_NOT_FOR_PROFIT",
        "businessSubCategory": "CHARITY_ALL_ACTIVITIES"
       }
    }
]

List of all profiles belonging to user.

Request

GET https://api.sandbox.transferwise.tech/v1/profiles

Create Identification Document

Example Request:

curl -X POST https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/verification-documents \
     -H "Authorization: Bearer <your api token>" \
     -H "Content-Type: application/json" \
     -d '{ 
            "firstName": "Oliver",
            "lastName": "Wilson",
            "type": "IDENTITY_CARD",
            "uniqueIdentifier": "AA299822313",
            "issueDate": "2017-12-31",
            "issuerCountry": "EE",
            "issuerState": "",
            "expiryDate": "2027-12-31"
        }'

Example Response:

{
  "errorMessage": null,
  "success": true   
}

Add identification document details to user profile. Applicable to personal profiles (not business) only.
Returns empty result if successful.

When sending a social security number (SSN) only type and uniqueIdentifier (only 9 digits no letters or symbols) are required.

Request

POST https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/verification-documents

Field Description Format
firstName Person first name in document Text
lastName Person last name in document Text
type Document type. Allowed Values:
  • DRIVERS_LICENCE
  • IDENTITY_CARD
  • GREEN_CARD
  • MY_NUMBER
  • PASSPORT
  • SSN
  • OTHER
Text
uniqueIdentifier Document number. Only digits when SSN. Text
issueDate Document issue date YYYY-MM-DD
issuerCountry Issued by country code. For example "US" Text
issuerState Issued by state code. For example "NY" Text
expiryDate Document expiry date. (optional) YYYY-MM-DD

Get business directors

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/directors \
     -H "Authorization: Bearer <your api token>" 

Example Response:

[
  {
    "id": 10,
    "firstName": "John",
    "lastName": "Doe",
    "dateOfBirth": "1982-05-20",
    "countryOfResidenceIso3Code": "usa"
  },
  {
    "id": 11,
    "firstName": "Jane",
    "lastName": "Doe",
    "dateOfBirth": "1981-12-07",
    "countryOfResidenceIso3Code": "usa"
  }
]

Returns the list of all directors associated with the business profile.

Request (Business)

GET https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/directors

Add business directors

Example Request:

curl -X POST https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/directors \
     -H "Authorization: Bearer <your api token>" \
     -H "Content-Type: application/json" \
     -d '[
             {
                 "firstName": "John",
                 "lastName": "Doe",
                 "dateOfBirth": "1982-05-20",
                 "countryOfResidenceIso3Code": "usa"
             },
             {
                 "firstName": "Jane",
                 "lastName": "Doe",
                 "dateOfBirth": "1981-12-07",
                 "countryOfResidenceIso3Code": "usa"
             }
        ]'

Example Response:

[
    {
        "id": 10,
        "firstName": "John",
        "lastName": "Doe",
        "dateOfBirth": "1982-05-20",
        "countryOfResidenceIso3Code": "usa"
    },
    {
        "id": 11,
        "firstName": "Jane",
        "lastName": "Doe",
        "dateOfBirth": "1981-12-07",
        "countryOfResidenceIso3Code": "usa"
    },
    {
        "id": 7,
        "firstName": "Oliver",
        "lastName": "Wilson",
        "dateOfBirth": "2017-12-31",
        "countryOfResidenceIso3Code": "gbr"
    }
]

Adds new directors to the business profile. Returns the list of all directors associated with the business profile.

Request (Business)

POST https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/directors

Field Description Format
firstName Director first name Text
lastName Director last name Text
dateOfBirth Date of birth YYYY-MM-DD
countryOfResidenceIso3Code 3 character country code Text

Update business directors

Example Request:

curl -X PUT https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/directors \
     -H "Authorization: Bearer <your api token>" \
     -H "Content-Type: application/json" \
     -d '[
             {
                 "firstName": "John",
                 "lastName": "Doe",
                 "dateOfBirth": "1982-05-20",
                 "countryOfResidenceIso3Code": "usa"
             },
             {
                 "firstName": "Jane",
                 "lastName": "Doe",
                 "dateOfBirth": "1981-12-07",
                 "countryOfResidenceIso3Code": "usa"
             }
        ]'

Example Response:

[
    {
        "id": 14,
        "firstName": "John",
        "lastName": "Doe",
        "dateOfBirth": "1982-05-20",
        "countryOfResidenceIso3Code": "usa"
    },
    {
        "id": 15,
        "firstName": "Jane",
        "lastName": "Doe",
        "dateOfBirth": "1981-12-07",
        "countryOfResidenceIso3Code": "usa"
    }
]

Overrides directors in the business profile. Returns the list of all directors associated with the business profile.

Request (Business)

PUT https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/directors

Field Description Format
firstName Director first name Text
lastName Director last name Text
dateOfBirth Date of birth YYYY-MM-DD
countryOfResidenceIso3Code 3 character country code Text

Get business ultimate beneficial owners

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/ubos \
     -H "Authorization: Bearer <your api token>" 

Example Response:

[
    {
        "id": "013ab1c2688d0185b582ee7e0bcb28b2",
        "name": "John Doe",
        "dateOfBirth": "1982-05-20",
        "countryOfResidenceIso3Code": "usa",
        "addressFirstLine": "123 Fake St",
        "postCode": "FK 12345",
        "ownershipPercentage": 30
    },
    {
        "id": "912ce3f31c8b3a10572137e78417caa3",
        "name": "Jane Doe",
        "dateOfBirth": "1981-12-07",
        "countryOfResidenceIso3Code": "usa",
        "addressFirstLine": "125 Fake St",
        "postCode": "FK 12545",
        "ownershipPercentage": 70
    }
]

Returns the list of all ultimate beneficial owners associated with the business profile.

Request (Business)

GET https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/ubos

Add business ultimate beneficial owners

Example Request:

curl -X POST https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/ubos \
     -H "Authorization: Bearer <your api token>" \
     -H "Content-Type: application/json" \
     -d '[
             {
                 "name": "John Doe",
                 "dateOfBirth": "1982-05-20",
                 "countryOfResidenceIso3Code": "usa",
                 "addressFirstLine": "123 Fake St",
                 "postCode": "FK 12345",
                 "ownershipPercentage": 30
             },
             {
                 "name": "Jane Doe",
                 "dateOfBirth": "1981-12-07",
                 "countryOfResidenceIso3Code": "usa",
                 "addressFirstLine": "125 Fake St",
                 "postCode": "FK 12545",
                 "ownershipPercentage": 40
             }
        ]'

Example Response:

[
     {
         "id": "f3e71aa1c97448d0b1eb5bdc0bacdcce",
         "name": "John Doe",
         "dateOfBirth": "1982-05-20",
         "countryOfResidenceIso3Code": "usa",
         "addressFirstLine": "123 Fake St",
         "postCode": "FK 12345",
         "ownershipPercentage": 30
     },
     {
         "id": "c6008d58a1664413b4c4dcacec1377f4",
         "name": "Jane Doe",
         "dateOfBirth": "1981-12-07",
         "countryOfResidenceIso3Code": "usa",
         "addressFirstLine": "125 Fake St",
         "postCode": "FK 12545",
         "ownershipPercentage": 40
     },
     {
         "id": "63bbdd1cf5ec4dd587597e74dbace376",
         "name": "Oliver Wilson",
         "dateOfBirth": "2017-12-31",
         "countryOfResidenceIso3Code": "gbr",
         "addressFirstLine": "222 Fake St",
         "postCode": "FK 22222",
         "ownershipPercentage": 30
     }
]

Adds new ultimate beneficial owners to the business profile. Returns the list of all ultimate beneficial owners associated with the business profile.

Request (Business)

POST https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/ubos

Field Description Format
name Owner full name Text
dateOfBirth Date of birth YYYY-MM-DD
countryOfResidenceIso3Code 3 character country code Text
addressFirstLine First line of address Text
postCode Address post code Text
ownershipPercentage Percentage of ownership Integer

Update business ultimate beneficial owners

Example Request:

curl -X PUT https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/ubos \
     -H "Authorization: Bearer <your api token>" \
     -H "Content-Type: application/json" \
     -d '[
             {
                 "name": "John Doe",
                 "dateOfBirth": "1982-05-20",
                 "countryOfResidenceIso3Code": "usa",
                 "addressFirstLine": "123 Fake St",
                 "postCode": "FK 12345",
                 "ownershipPercentage": 30
             },
             {
                 "name": "Jane Doe",
                 "dateOfBirth": "1981-12-07",
                 "countryOfResidenceIso3Code": "usa",
                 "addressFirstLine": "125 Fake St",
                 "postCode": "FK 12545",
                 "ownershipPercentage": 70
             }
        ]'

Example Response:

[
     {
         "id": "ff01cf3f206b40c090a14a1e51163e9e",
         "name": "John Doe",
         "dateOfBirth": "1982-05-20",
         "countryOfResidenceIso3Code": "usa",
         "addressFirstLine": "123 Fake St",
         "postCode": "FK 12545",
         "ownershipPercentage": 30
     },
     {
         "id": "c36b687d28ad44ad8c3864411f5f2612",
         "name": "Jane Doe",
         "dateOfBirth": "1981-12-07",
         "countryOfResidenceIso3Code": "usa",
         "addressFirstLine": "125 Fake St",
         "postCode": "FK 12545",
         "ownershipPercentage": 70
     }
]

Overrides ultimate beneficial owners in the business profile. Returns the list of all ultimate beneficial owners associated with the business profile.

Request (Business)

PUT https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/ubos

Field Description Format
name Owner full name Text
dateOfBirth Date of birth YYYY-MM-DD
countryOfResidenceIso3Code 3 character country code Text
addressFirstLine First line of address Text
postCode Address post code Text
ownershipPercentage Percentage of ownership Integer

Open update window

Example Request:

curl -X POST https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/update-window \
     -H "Authorization: Bearer <your api token>" 

Example Response:


Opens the update window for updating the profile information: details, addresses, directors, owners, others.

Request

POST https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/update-window

Close update window

Example Request:

curl -X DELETE https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/update-window \
     -H "Authorization: Bearer <your api token>" 

Example Response:


Deletes the update window for updating the profile.

Request

DELETE https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/update-window

Profile extensions

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/extension-requirements \
     -H "Authorization: Bearer <your api token>"

Example Response:

[
  {
    "type": "profile-extensions-requirements",
    "usageInfo": null,
    "fields": [
      {
        "name": "Tell us what you're using TransferWise for",
        "group": [
          {
            "key": "accountPurpose",
            "name": "Account Purpose",
            "type": "select",
            "refreshRequirementsOnChange": false,
            "required": true,
            "displayFormat": null,
            "example": null,
            "minLength": null,
            "maxLength": null,
            "validationRegexp": null,
            "validationAsync": null,
            "valuesAllowed": [
              {
                "key": "CONTRIBUTING_TO_PERSONAL_SAVINGS",
                "name": "Contributing to personal savings"
              },
              {
                "key": "GENERAL_MONTHLY_LIVING_EXPENSES",
                "name": "General monthly living expenses"
              },
              {
                "key": "INVESTING_IN_FUNDS_STOCKS_BONDS_OPTIONS_FUTURES_OR_OTHER",
                "name": "Investing in funds stocks bonds options futures or other"
              },
              {
                "key": "PAYING_FOR_GOODS_OR_SERVICES_ABROAD",
                "name": "Paying for goods or services abroad"
              },
              {
                "key": "PAYING_RENT_MORTGAGE_BANK_LOAN_INSURANCE_CREDIT",
                "name": "Paying rent mortgage bank loan insurance credit"
              },
              {
                "key": "PAYING_RENT_UTILITIES_OR_PROPERTY_CHARGES",
                "name": "Paying rent utilities or property charges"
              },
              {
                "key": "RECEIVE_SALARY_IN_DIFFERENT_CURRENCY",
                "name": "Receive salary in different currency"
              },
              {
                "key": "RECEIVE_PENSION_IN_DIFFERENT_CURRENCY",
                "name": "Receive pension in different currency"
              },
              {
                "key": "SENDING_MONEY_REGULARLY_TO_FAMILY",
                "name": "Sending money regularly to family"
              },
              {
                "key": "SENDING_MONEY_TO_MY_OWN_ACCOUNT_TO_BENEFIT_FROM_EXHCANGE_RATE",
                "name": "Sending money to my own account to benefit from exchange rate"
              }
            ]
          }
        ]
      }
    ]
  }
]

After having a profile created, in some situations we can need more specific information about it. In order to know which fields are required for a given profile, and to send the information over, we expose a few endpoints:

GET https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/extension-requirements
POST https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/extension-requirements

and

POST https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/extensions
GET https://api.sandbox.transferwise.tech/v1/profiles/{profileId}/extensions

The GET and POST profile extension-requirements endpoints help you to figure out which fields are required to create a valid profile for different regions. You can use this data to build a dynamic user interface on top of these endpoints.

The POST and GET profile extensions endpoints allow you to send the extra profile information and retrieve it, respectively.

This format for dynamic forms is the same as the one used for recipient creation. See Recipient.Requirements and Using account requirements

This is a step-by-step guide on how these endpoints work.

Using profile extension requirements

  1. First create a profile. See User Profiles Create (Personal) and User Profiles Create (Business)

  2. Call GET /v1/profiles/{profileId}/extension-requirements to get the list of fields you need to fill with values in the "details" section for adding information that will make a profile valid.

  3. Some fields require multiple levels of fields in the details request. This should be handled by the client based on the refreshRequirementsOnChange field. A top level field can have this field set to true, indicating that there are additional fields required depending on the selected value. To manage this you should create a request with all of the initially requested data and call the POST extension-requirements endpoint. You will be returned a response similar the previously returned data from GET extension-requirements but with additional fields.

  4. Once you have built your full profile extension details object you can add it to add information to the profile.

This is a valid request to add information to a profile:

POST v1/profiles/{profileId}/extensions

{
    "details": {
        "accountPurpose": "SENDING_MONEY_REGULARLY_TO_FAMILY"
    }
}

Building an user interface

When requesting the form data from the extension-requirements endpoint, the response defines different types of extensions that can be added. Each extension type then has multiple fields describing the form elements required to be shown to collect information from the user. Each field will have a type value, these tell you the field type that your front end needs to render to be able to collect the data. A number of field types are permitted, these are:

type UI element
text A free text box
select A selection box/dialog
radio A radio button choice between options
date A text box with a date picker

Example data is also included in each field which should be shown to the user, along with a regex or min and mex length constraints that should be applied as field level validations. You can optionally implement the dynamic validation using the validationAsync field, however these checks will also be done when a completed profile extension is submitted to POST /v1/profiles/{profileId}/extensions.

Response

Field Description Format
type "profile-extensions-requirements" Text
fields[n].name Field description Text
fields[n].group[n].key Key is name of the field you should include in the JSON Text
fields[n].group[n].type Display type of field (e.g. text, select, etc) Text
fields[n].group[n].refreshRequirementsOnChange Tells you whether you should call POST extension-requirements once the field value is set to discover required lower level fields. Boolean
fields[n].group[n].required Indicates if the field is mandatory or not Boolean
fields[n].group[n].displayFormat Display format pattern. Text
fields[n].group[n].example Example value. Text
fields[n].group[n].minLength Min valid length of field value. Integer
fields[n].group[n].maxLength Max valid length of field value. Integer
fields[n].group[n].validationRegexp Regexp validation pattern. Text
fields[n].group[n].validationAsync Validator URL and parameter name you should use when submitting the value for validation Text
fields[n].group[n].valuesAllowed[n].key List of allowed values. Value key Text
fields[n].group[n].valuesAllowed[n].name List of allowed values. Value name. Text

Addresses

Create

Example Request:

curl -X POST https://api.sandbox.transferwise.tech/v1/addresses \
     -H "Authorization: Bearer <your api token>" \
     -H "Content-Type: application/json" \
     -d '{ 
          "profile": <your profile id>,
          "details": {
            "country": "EE",
            "firstLine": "Narva mnt 5-1",
            "postCode": "10113",
            "city": "Tallinn"
          }
        }'

Example Response:

{
  "id": 236532,
  "profile": <your profile id>,
  "details": {
    "country": "EE",
    "firstLine": "Narva mnt 5-1",
    "postCode": "10113",
    "city": "Tallinn",
    "state": "",
    "occupation": null
  }
}

Adds address info to user profile. List of required fields are slightly different for different countries.
For example state field is required for US, CA, BR and AU addresses but not for other countries. Please look at Addresses.Requirements to figure out which fields are required to create addresses in specific country.

Request

POST https://api.sandbox.transferwise.tech/v1/addresses

Field Description Format
profile User profile id. Integer
details.country 2 digit ISO country code. Text
details.firstLine Address line: street, house, apartment. Text
details.postCode Zip code Text
details.city City name Text
details.state State code. Required if country is US, CA, AU, BR Text
details.occupation User occupation. Required for US, CA, JP Text

Response

Field Description Format
id Address id Integer
profile User profile id. Integer
details.country 2 digit ISO country code. Text
details.firstLine Address line: street, house, apartment. Text
details.postCode Zip code Text
details.city City name Text
details.state State code. Required if country is US, CA, AU, BR Text
details.occupation User occupation. Required for US, CA, JP Text

Get By Id

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v1/addresses/{addressId} \
     -H "Authorization: Bearer <your api token>" 

Example Response:

{
  "id": 236532,
  "profile": <your profile id>,
  "details": {
    "country": "EE",
    "firstLine": "Narva mnt 5-1",
    "postCode": "10113",
    "city": "Tallinn",
    "state": "",
    "occupation": null
  }
}

Get address info by id.

Request

GET https://api.sandbox.transferwise.tech/v1/addresses/{addressId}

List

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v1/addresses?profile={profileId} \
     -H "Authorization: Bearer <your api token>" 

Example Response:

[
    {
        "id": 7099091,
        "profile": <your profile id>,
        "details": {
            "country": "EE",
            "firstLine": "Veerenni 29",
            "postCode": "12991",
            "city": "Tallinn",
            "state": null,
            "occupation": null
        }
    }
]

List of addresses belonging to user profile.

Request

GET https://api.sandbox.transferwise.tech/v1/addresses?profile={profileId}

Requirements

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v1/address-requirements \
     -H "Authorization: Bearer <your api token>" 

Example Response:

[
  {
    "type": "address",
    "fields": [
      {
        "name": "Country",
        "group": [
          {
            "key": "country",
            "type": "select",
            "refreshRequirementsOnChange": true,
            "required": true,
            "displayFormat": null,
            "example": "Germany",
            "minLength": null,
            "maxLength": null,
            "validationRegexp": null,
            "validationAsync": null,
            "valuesAllowed": [
              {
                "key": "AX",
                "name": "Åland Islands"
              },
              ...
              {
                "key": "ZM",
                "name": "Zambia"
              }
            ]
          }
        ]
      },
      {
        "name": "City",
        "group": [
          {
            "key": "city",
            "type": "text",
            "refreshRequirementsOnChange": false,
            "required": true,
            "displayFormat": null,
            "example": "London",
            "minLength": null,
            "maxLength": null,
            "validationRegexp": null,
            "validationAsync": null,
            "valuesAllowed": null
          }
        ]
      },
      {
        "name": "Postal code",
        "group": [
          {
            "key": "postCode",
            "type": "text",
            "refreshRequirementsOnChange": false,
            "required": true,
            "displayFormat": null,
            "example": "10025",
            "minLength": null,
            "maxLength": null,
            "validationRegexp": null,
            "validationAsync": null,
            "valuesAllowed": null
          }
        ]
      }
      ...
    ]
  }
]

Request

GET https://api.sandbox.transferwise.tech/v1/address-requirements
POST https://api.sandbox.transferwise.tech/v1/address-requirements

GET and POST address-requirements endpoints help you to figure out which fields are required to create a valid address for different countries. You could even build a dynamic user interface on top of these endpoints. This is a step-by-step guide on how these endpoints work.

  1. Call GET /v1/address-requirements to get list of fields you need to fill with values in "details" section for creating a valid address. Response contains 4 required top level fields:

    • country (select field with list of values)
    • city (text field)
    • postCode (text field)
    • firstLine (text field)
  2. Analyze the list of fields. Because refreshRequirementsOnChange for field 'country' is marked as true then this indicates that there are additional fields required depending on the selected value.

  3. Call POST /v1/address-requirements with selected country value to expose sub fields.
    For example posting {"details": {"country" : "US"}} will also add "state" to list of fields.
    But posting {"details": {"country" : "GB"}} will not.

  4. If you choose "US" as country you will notice that "state" field also has refreshRequirementsOnChange=true. This means you would need to make another POST call to /v1/address-requirements with a specific state value.
    For example posting {"details": { "country" : "US", "state": "AZ" }} will also add "occupation" to list of fields.
    But posting {"details": { "country" : "US", "state": "AL" }} will not.

  5. So once you get to the point where you have provided values for all fields which have refreshRequirementsOnChange=true then you have complete set of fields to compose a valid request to create an address object. For example this is a valid request to create address in US Arizona:
    POST /v1/addresses:
    { "profile" : your-profile-id,
    "details": {
    "country" : "US",
    "state": "AZ",
    "city": "Phoenix",
    "postCode": "10025",
    "firstLine": "50 Sunflower Ave.",
    "occupation": "software engineer"
    } }

Response

Field Description Format
type "address" Text
fields[n].name Field description Text
fields[n].group[n].key Key is name of the field you should include in the JSON Text
fields[n].group[n].type Display type of field (e.g. text, select, etc) Text
fields[n].group[n].refreshRequirementsOnChange Tells you whether you should call POST address-requirements once the field value is set to discover required lower level fields. Boolean
fields[n].group[n].required Indicates if the field is mandatory or not Boolean
fields[n].group[n].displayFormat Display format pattern. Text
fields[n].group[n].example Example value. Text
fields[n].group[n].minLength Min valid length of field value. Integer
fields[n].group[n].maxLength Max valid length of field value. Integer
fields[n].group[n].validationRegexp Regexp validation pattern. Text
fields[n].group[n].validationAsync Validator URL and parameter name you should use when submitting the value for validation Text
fields[n].group[n].valuesAllowed[n].key List of allowed values. Value key Text
fields[n].group[n].valuesAllowed[n].name List of allowed values. Value name. Text

Quotes

Create

Example Request:

curl -X POST https://api.sandbox.transferwise.tech/v2/quotes \
     -H "Authorization: Bearer <your api token>" \
     -H "Content-Type: application/json" \
     -d '{
          "sourceCurrency": "GBP",
          "targetCurrency": "USD",
          "sourceAmount": 100,
          "targetAmount": null,
          "profile": 101
        }'

Example Response:

{
    "id": "11144c35-9fe8-4c32-b7fd-d05c2a7734bf",
    "sourceCurrency": "GBP",
    "targetCurrency": "USD",
    "sourceAmount": 100,
    "payOut": "BANK_TRANSFER",
    "rate": 1.30445,
    "createdTime": "2019-04-05T13:18:58Z",
    "user": 55,
    "profile": 101,
    "rateType": "FIXED",
    "rateExpirationTime": "2019-04-08T13:18:57Z",
    "guaranteedTargetAmountAllowed": true,
    "targetAmountAllowed": true,
    "guaranteedTargetAmount": false,
    "providedAmountType": "SOURCE",
    "paymentOptions": [
        {
            "disabled": false,
            "estimatedDelivery": "2019-04-08T12:30:00Z",
            "formattedEstimatedDelivery": "by Apr 8",
            "estimatedDeliveryDelays": [],
            "fee": {
                "transferwise": 0.92,
                "payIn": 0,
                "discount": 0,
                "total": 0.92
            },
            "sourceAmount": 100,
            "targetAmount": 129.24,
            "sourceCurrency": "GBP",
            "targetCurrency": "USD",
            "payIn": "BANK_TRANSFER",
            "payOut": "BANK_TRANSFER",
            "allowedProfileTypes": [
                "PERSONAL",
                "BUSINESS"
            ],
            "payInProduct": "CHEAP",
            "feePercentage": 0.0092
        },
        {
            "disabled": true,
            "estimatedDelivery": null,
            "formattedEstimatedDelivery": null,
            "estimatedDeliveryDelays": [],
            "fee": {
                "transferwise": 1.11,
                "payIn": 0,
                "discount": 0,
                "total": 1.11
            },
            "sourceAmount": 100,
            "targetAmount": 129,
            "sourceCurrency": "GBP",
            "targetCurrency": "USD",
            "payIn": "BALANCE",
            "payOut": "BANK_TRANSFER",
            "allowedProfileTypes": [
                "PERSONAL",
                "BUSINESS"
            ],
            "disabledReason": {
                "code": "error.payInmethod.disabled",
                "message": "Open a borderless account and add funds to instantly pay for your transfers."
            },
            "payInProduct": "BALANCE",
            "feePercentage": 0.0111
        }
    ],
    "status": "PENDING",
    "expirationTime": "2019-04-05T13:48:58Z",
    "notices": [{
        "text": "You can have a maximum of 3 open transfers with a guaranteed rate. After that, they'll be transferred using the live rate. Complete or cancel your other transfers to regain the use of guaranteed rate.",
        "link": null,
        "type": "WARNING"
    }]
}


The quote resource defines the basic information required for a TransferWise transfer - the currencies to send between, the amount to send and the profile who is sending the money. The profile must be included when creating a quote.

Quote is one of the required resources to create a transfer, along with the recipient who is to receive the funds.

The quote response contains other information such as the exchange rate, the estimated delivery time and the methods the user can pay for the transfer. Not all of this information may apply to the bank use case.

Upon creating a quote the current mid-market exchange rate is locked and will be used for the transfer that is created from the quote. The rate will be locked for 30 minutes to give a user time to complete the transfer creation flow.

Request

POST https://api.sandbox.transferwise.tech/v2/quotes

Field Description Format
profile Personal or business profile id of the sender - required. Integer
sourceCurrency Source (sending) currency code. Text
targetCurrency Target (receiving) currency code. Text
targetAmount Amount in target currency. Decimal
sourceAmount Amount in source currency.
Either sourceAmount or targetAmount is required, never both.
Decimal

Response - useful fields

The following describes the fields of the quote response that may be useful when building your integration. The array of PaymentOption objects returned can mostly be ignored when building a bank integration, you should generally only be concerned with the option which has both payIn and payOut of BANK_TRANSFER. When showing the price of a transfer always show the total fees of a payment option.

For most use cases a pay in and pay out of BANK_TRANSFER will be the correct option to show the fees to the user, although if the user is sending a currency to a country other than where the currency is from the payment options will change. For example sending USD to a country other than the United States is supported but with different fees to domestic USD transfers. Please see the later section on Global Currencies to learn more about how to offer this useful feature.

Field Description Format
id ID of this quote (GUID format). Text
sourceCurrency Source (sending) currency code. Text
targetCurrency Target (receive) currency code. Text
sourceAmount Amount in source currency to send. Decimal
targetAmount Amount in target currency to be receieved. Decimal
payOut Mechansim we us to deliver the transfer. Not usually of interest to the user. Text
rate Exchange rate value used for the conversion. Decimal
createdTime Quote created timestamp. Timestamp
user User ID who created the quote. Integer
profile Personal or business profile id. Integer
rateExpirationTime Time the locked rate will expire. Timestamp
providedAmountType Whether the quote was creates as "SOURCE" or "TARGET". Text
paymentOptions List of the methods a user can pay for the transfer. By default you should take the option with payIn and payOut of BANK_TRANSFER, unless we instruct you otherwise. [PaymentOption]
option.disabled Whether this option is enabled or not for this quote. Boolean
option.estimatedDelivery The estimated delivery time for this combination of payin and payout methods, assuming payIn is performed now. Timestamp
option.formattedEstimatedDelivery A string to display to users for the estimated delivery date. Text
option.estimatedDeliveryDelays Array of strings for delivery delays to display to users. [Text]
option.fee Object containing fee information. Fee
option.fee.transferwise The fee to be paid by the user based on the current state of the quote. Decimal
option.fee.payIn The fee for this payment option, based on the product type of the payment option. Decimal
option.fee.discount Any discounts that have been applied to this quote for the user. Decimal
option.fee.total The total fees to be paid - use this figure when displaying fees on your app. Decimal
option.sourceAmount sourceAmount when using this payment option Decimal
option.targetAmount targetAmount when using this payment option Decimal
option.payIn Type of pay in method for this payment option. Text
option.payOut Type of pay out method for this payment option. Text
option.allowedProfileTypes Array of the allowed types of profile to use this payment option for this quote "PERSONAL", "BUSINESS" or both. [Text]
option.disabledReason Object present if a payment option is disabled Disabled Reason
option.disabledReason.code Code to denote the reason a payment method is unavailable Text
option.disabledReason.message User friendly message to display when a method is unavailable Text
status Current status of this quote, one of: "PENDING", "ACCEPTED", "FUNDED" or "EXPIRED" Text
expirationTime The time the quote expires Timestamp
notices Array of messages to display the user in case of useful information based on their selections. May be empty ([]) if there are no messages. [QuoteNotice]
notice.text The message to display Text
notice.link URL that provides more information to the message. May be null if there's no URL. Text
notice.type Type of message, WARNING or INFO or BLOCKED. If it is BLOCKED, don't allow the quote to be used to create the transfer Text

Update Quote

Example Request:

curl -X PATCH \
  https://api.sandbox.transferwise.tech/v2/quotes/11144c35-9fe8-4c32-b7fd-d05c2a7734bf \
  -H 'Authorization: Bearer <your api token>' \
  -H 'Content-Type: application/merge-patch+json' \
  -d '{ 
        "targetAccount": 12345,
        "profile": 101
      }'

Example Response:

{
    "id": "11144c35-9fe8-4c32-b7fd-d05c2a7734bf",
    "sourceCurrency": "GBP",
    "targetCurrency": "USD",
    "sourceAmount": 100,
    "payOut": "BANK_TRANSFER",
    "rate": 1.30445,
    "createdTime": "2019-04-05T13:18:58Z",
    "user": 55,
    "profile": 101,
    "rateType": "FIXED",
    "rateExpirationTime": "2019-04-08T13:18:57Z",
    "guaranteedTargetAmountAllowed": true,
    "targetAmountAllowed": true,
    "guaranteedTargetAmount": false,
    "providedAmountType": "SOURCE",
    "targetAccount": 12345,
    "paymentOptions": [
        {
            "disabled": false,
            "estimatedDelivery": "2019-04-08T12:30:00Z",
            "formattedEstimatedDelivery": "by Apr 8",
            "estimatedDeliveryDelays": [],
            "fee": {
                "transferwise": 0.92,
                "payIn": 0,
                "discount": 0,
                "total": 0.92
            },
            "sourceAmount": 100,
            "targetAmount": 129.24,
            "sourceCurrency": "GBP",
            "targetCurrency": "USD",
            "payIn": "BANK_TRANSFER",
            "payOut": "BANK_TRANSFER",
            "allowedProfileTypes": [
                "PERSONAL",
                "BUSINESS"
            ],
            "payInProduct": "CHEAP",
            "feePercentage": 0.0092
        },
        {
            "disabled": true,
            "estimatedDelivery": null,
            "formattedEstimatedDelivery": null,
            "estimatedDeliveryDelays": [],
            "fee": {
                "transferwise": 1.11,
                "payIn": 0,
                "discount": 0,
                "total": 1.11
            },
            "sourceAmount": 100,
            "targetAmount": 129,
            "sourceCurrency": "GBP",
            "targetCurrency": "USD",
            "payIn": "BALANCE",
            "payOut": "BANK_TRANSFER",
            "allowedProfileTypes": [
                "PERSONAL",
                "BUSINESS"
            ],
            "disabledReason": {
                "code": "error.payInmethod.disabled",
                "message": "Open a borderless account and add funds to instantly pay for your transfers."
            },
            "payInProduct": "BALANCE",
            "feePercentage": 0.0111
        }
    ],
    "status": "PENDING",
    "expirationTime": "2019-04-05T13:48:58Z",
    "notices": []
}

You can update a quote using a PATCH call to add a recipient to update the saved quote's data based on who and where the money will be sent. Updating the quote with a recipient may cause the available payment options, prices and estimated delivery times to change from the original quoted amounts. This is due to the fact that sending some currencies to some destinations costs a different amount based on the payment networks we use, for example sending USD to a country outside the USA uses international rather than domestic payment networks and as such costs more.

Request

PATCH https://api.sandbox.transferwise.tech/v2/quotes/{quoteId}

Get By Id

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v2/quotes/{quoteId} \
     -H "Authorization: Bearer <your api token>" 

Example Response:

{
    "id": "11144c35-9fe8-4c32-b7fd-d05c2a7734bf",
    "sourceCurrency": "GBP",
    "targetCurrency": "USD",
    "sourceAmount": 100,
    "payOut": "BANK_TRANSFER",
    "rate": 1.30445,
    "createdTime": "2019-04-05T13:18:58Z",
    "user": 55,
    "profile": 101,
    "rateType": "FIXED",
    "rateExpirationTime": "2019-04-08T13:18:57Z",
    "guaranteedTargetAmountAllowed": true,
    "targetAmountAllowed": true,
    "guaranteedTargetAmount": false,
    "providedAmountType": "SOURCE",
    "paymentOptions": [
        {
            "disabled": false,
            "estimatedDelivery": "2019-04-08T12:30:00Z",
            "formattedEstimatedDelivery": "by Apr 8",
            "estimatedDeliveryDelays": [],
            "fee": {
                "transferwise": 0.92,
                "payIn": 0,
                "discount": 0,
                "total": 0.92
            },
            "sourceAmount": 100,
            "targetAmount": 129.24,
            "sourceCurrency": "GBP",
            "targetCurrency": "USD",
            "payIn": "BANK_TRANSFER",
            "payOut": "BANK_TRANSFER",
            "allowedProfileTypes": [
                "PERSONAL",
                "BUSINESS"
            ],
            "payInProduct": "CHEAP",
            "feePercentage": 0.0092
        },
        {
            "disabled": true,
            "estimatedDelivery": null,
            "formattedEstimatedDelivery": null,
            "estimatedDeliveryDelays": [],
            "fee": {
                "transferwise": 1.11,
                "payIn": 0,
                "discount": 0,
                "total": 1.11
            },
            "sourceAmount": 100,
            "targetAmount": 129,
            "sourceCurrency": "GBP",
            "targetCurrency": "USD",
            "payIn": "BALANCE",
            "payOut": "BANK_TRANSFER",
            "allowedProfileTypes": [
                "PERSONAL",
                "BUSINESS"
            ],
            "disabledReason": {
                "code": "error.payInmethod.disabled",
                "message": "Open a borderless account and add funds to instantly pay for your transfers."
            },
            "payInProduct": "BALANCE",
            "feePercentage": 0.0111
        }
    ],
    "status": "PENDING",
    "expirationTime": "2019-04-05T13:48:58Z",
    "notices": []
}

Get quote info by id.

Request

GET https://api.sandbox.transferwise.tech/v2/quotes/{quoteId}

Request

GET https://api.sandbox.transferwise.tech/v2/quotes/{quoteId}/pay-in-methods

Response

Field Description Format
type Currently always 'transfer' meaning the only pay-in option is via bank transfer. Text
details.payInReference Reference text to be used when sending your bank transfer to TransferWise. Text

Get Temporary Quote

Use this endpoint to get example quotes for people to see the exchange rate and fees TransferWise offers before a user has created or linked an account. This can drive a version of the quote screen that shows the user what TransferWise offers before they sign up. Note that this endpoint does not require a token to create the resource, however, since it is just an example, the returned quote has no ID so can't be used later to create a transfer.

Example Request:

curl -X POST \
  https://api.transferwise.com/v2/quotes/ \
  -H 'Content-type: application/json' \
  -d '{
    "sourceCurrency": "GBP",
    "targetCurrency": "USD",
    "sourceAmount": null,
    "targetAmount": 110
}'

Example Response:

{
    "sourceCurrency": "GBP",
    "targetCurrency": "USD",
    "targetAmount": 110,
    "payOut": "BANK_TRANSFER",
    "rate": 1.30745,
    "createdTime": "2019-04-09T11:46:38Z",
    "rateType": "FIXED",
    "guaranteedTargetAmountAllowed": true,
    "targetAmountAllowed": true,
    "guaranteedTargetAmount": false,
    "providedAmountType": "TARGET",
    "paymentOptions": [
        {
            "disabled": false,
            "estimatedDelivery": "2019-04-10T12:30:00Z",
            "formattedEstimatedDelivery": "by Apr 10",
            "estimatedDeliveryDelays": [],
            "fee": {
                "transferwise": 0.87,
                "payIn": 0,
                "discount": 0,
                "total": 0.87
            },
            "sourceAmount": 85,
            "targetAmount": 110,
            "sourceCurrency": "GBP",
            "targetCurrency": "USD",
            "payIn": "BANK_TRANSFER",
            "payOut": "BANK_TRANSFER",
            "allowedProfileTypes": [
                "PERSONAL",
                "BUSINESS"
            ],
            "payInProduct": "CHEAP",
            "feePercentage": 0.0102
        },
        {
            "disabled": true,
            "estimatedDelivery": null,
            "formattedEstimatedDelivery": null,
            "estimatedDeliveryDelays": [],
            "fee": {
                "transferwise": 1.15,
                "payIn": 0,
                "discount": 0,
                "total": 1.15
            },
            "sourceAmount": 85.28,
            "targetAmount": 110,
            "sourceCurrency": "GBP",
            "targetCurrency": "USD",
            "payIn": "BALANCE",
            "payOut": "BANK_TRANSFER",
            "allowedProfileTypes": [
                "PERSONAL",
                "BUSINESS"
            ],
            "disabledReason": {
                "code": "error.payInmethod.disabled",
                "message": "Open a borderless account and add funds to instantly pay for your transfers."
            },
            "payInProduct": "BALANCE",
            "feePercentage": 0.0135
        }
    ],
    "notices": []
}

Request

POST https://api.sandbox.transferwise.tech/v2/quotes

Field Description Format
sourceCurrency Source (sending) currency code Text
targetCurrency Target (receiving) currency code Text
sourceAmount Amount in source currency.
Either sourceAmount or targetAmount is required, never both.
Decimal
targetAmount Amount in target currency Decimal

Response

See Create quote's response field information.

















































Recipient Accounts

These endpoints use a mixture of our v1 and v2 api - please ensure you address the right version to get the expected results. All recipient IDs are cross compatible with v1 and v2.

Create

Example Request (Create GBP recipient):

curl -X POST https://api.sandbox.transferwise.tech/v1/accounts \
     -H "Authorization: Bearer <your api token>" \
     -H "Content-Type: application/json" \
     -d '{ 
          "currency": "GBP", 
          "type": "sort_code", 
          "profile": <your profile id>,
          "ownedByCustomer": true, 
          "accountHolderName": "Ann Johnson",
           "details": { 
              "legalType": "PRIVATE",
              "sortCode": "231470", 
              "accountNumber": "28821822" 
           } 
         }'

Example Response (Create GBP recipient):

{
    "id": 13967081,
    "business": null,
    "profile": <your profile id>,
    "accountHolderName": "Ann Johnson",
    "currency": "GBP",
    "country": "GB",
    "type": "sort_code",
    "details": {
        "address": {
            "country": null,
            "countryCode": null,
            "firstLine": null,
            "postCode": null,
            "city": null,
            "state": null
        },
        "email": null,
        "legalType": "PRIVATE",
        "accountNumber": "28821822",
        "sortCode": "231470",
        "abartn": null,
        "accountType": null,
        "bankgiroNumber": null,
        "ifscCode": null,
        "bsbCode": null,
        "institutionNumber": null,
        "transitNumber": null,
        "phoneNumber": null,
        "bankCode": null,
        "russiaRegion": null,
        "routingNumber": null,
        "branchCode": null,
        "cpf": null,
        "cardNumber": null,
        "idType": null,
        "idNumber": null,
        "idCountryIso3": null,
        "idValidFrom": null,
        "idValidTo": null,
        "clabe": null,
        "swiftCode": null,
        "dateOfBirth": null,
        "clearingNumber": null,
        "bankName": null,
        "branchName": null,
        "businessNumber": null,
        "province": null,
        "city": null,
        "rut": null,
        "token": null,
        "cnpj": null,
        "payinReference": null,
        "pspReference": null,
        "orderId": null,
        "idDocumentType": null,
        "idDocumentNumber": null,
        "targetProfile": null,
        "taxId": null,
        "iban": null,
        "bic": null,
        "IBAN": null,
        "BIC": null
    },
    "user": <your user ID>,
    "active": true,
    "ownedByCustomer": true
}

Recipient is a person or institution who is the ultimate beneficiary of your payment.

Recipient data includes three data blocks.

1) General Data

Owned by customer is a boolean to flag whether this recipient is the same entity (person or business) as the one sending the funds. i.e. A user sending money to their own account in another country/currency. This can be used to separate these recipients in your UI.

2) Bank account data

There are many different variations of bank account details needed depending on recipient target currency. For example:

3) Address data Recipient address data is required only if target currency is USD, PHP, THB or TRY, or if the source currency is USD or AUD.

When creating recipient, the following general rules should be applied to "accountHolderName" field:

Recipient requirements will vary depending on recipient type. A GBP example is provided here.
As you can see many of the fields are null, in order to know which fields are required for which currency we expose the Recipients.Requirements endpoint.

Request

POST https://api.sandbox.transferwise.tech/v1/accounts

Field Description Format Optional
currency 3 character currency code Text false
type Recipient type Text false
profile Personal or business profile id Integer false
accountHolderName Recipient full name Text false
ownedByCustomer Whether this account is owned by the sending user Text true
details Currency specific fields Object false
details.legalType Recipient legal type: PRIVATE or BUSINESS Text false
details.sortCode Recipient bank sort code (GBP example) Text false
details.accountNumber Recipient bank account no (GBP example) Text false

Response

Recipient account id is needed for creating transfers in step 3.

Field Description Format
id accountId Integer
profile Personal or business profile id Integer
acccountHolderName Recipient full name Text
currency 3 character country code Text
country 2 character currency code Text
type Recipient type Text
ownedByCustomer Whether this account is owned by the sending user Text
details Currency specific fields Object
details.legalType Recipient legal type Text
details.sortCode Recipient bank sort code (GBP example) Text
details.accountNumber Recipient bank account no (GBP example) Text

Get By Id

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v2/accounts/{accountId} \
     -H "Authorization: Bearer <your api token>" 

Example Response:

{
    "id": 100,
    "creatorId": 300,
    "profileId": 305,
    "name": {
        "fullName": "Firstname Lastname",
        "givenName": null,
        "familyName": null,
        "middleNames": [],
        "patronymicName": null
    },
    "currency": "GBP",
    "country": "GB",
    "type": "SortCode",
    "legalEntityType": "INSTITUTION",
    "active": true,
    "details": {
        "accountNumber": "00000001",
        "sortCode": "040004"
    },
    "commonFieldMap": {
        "accountNumberField": "accountNumber",
        "bankCodeField": "sortCode"
    },
    "hash": "114969645b7d4105aec003c6a03bbd7c66fa934004b4518b4eb38ed8d6a31c51",
    "accountSummary": "(04-00-04) 00000001",
    "ownedByCustomer": false
}

Get recipient account info by id. Note here we use the v2 endpoint to get the recipient details despite using v1 to create it. The new v2 endpoint provides useful features such as the accountSummary field which can be used to represent the recipient's details in your UI.

In addition the commonFieldMap field allows you to break this down further in order to consistently know which fields to show to users as the account number and bank code, regardless if the field name changes between different recipient type details.

This response also includes a hash of a recipient, this can be used to track if the recipient details change, which they can in some scenarios. This is a security feature to allow you to re-run any checks your system does on the recipient to validate them against, for example, fraud engines. The hash will remain constant unless the recipient's name or information in the details object changes, excluding the recipient's postal address.

Request

GET https://api.sandbox.transferwise.tech/v2/accounts/{accountId}

List

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v2/accounts/?profileId=305 \
     -H "Authorization: Bearer <your api token>" 

Example Response:

{
  "content": [
    {
      "id": 100,
      "creatorId": 300,
      "profileId": 305,
      "name": {
          "fullName": "Firstname Lastname",
          "givenName": null,
          "familyName": null,
          "middleNames": [],
          "patronymicName": null
      },
      "currency": "GBP",
      "country": "GB",
      "type": "SortCode",
      "legalEntityType": "INSTITUTION",
      "active": true,
      "details": {
          "accountNumber": "00000001",
          "sortCode": "040004"
      },
      "commonFieldMap": {
          "accountNumberField": "accountNumber",
          "bankCodeField": "sortCode"
      },
      "hash": "114969645b7d4105aec003c6a03bbd7c66fa934004b4518b4eb38ed8d6a31c51",
      "accountSummary": "(04-00-04) 00000001",
      "ownedByCustomer": false
    },
    {
      "id": 150,
      "creatorId": 300,
      "profileId": 305,
      "name": {
          "fullName": "Firstname Lastname",
          "givenName": "Firstname",
          "familyName": "Lastname",
          "middleNames": [],
          "patronymicName": null
      },
      "address": {
          "country": "BD",
          "firstLine": "1 A road",
          "postCode": "11111",
          "city": "Dhaka",
          "state": null
      },
      "currency": "BDT",
      "country": "BD",
      "type": "BangladeshLocal",
      "legalEntityType": "INSTITUTION",
      "active": true,
      "details": {
          "branchCode": "999999999",
          "bankCode": "001",
          "accountNumber": "0000000001"
      },
      "commonFieldMap": {
          "accountNumberField": "accountNumber",
          "bankCodeField": "bankCode",
          "branchCodeField": "branchCode"
      },
      "hash": "7fc879c640346ca1773b478a18acc0f9c3f02c10bf963c9e8816d03c463021f1",
      "accountSummary": "(001) 0000000001",
      "ownedByCustomer": true
    }
  ],
  "seekPositionForNext": 151,
  "sort": {
      "sorted": false,
      "unsorted": true
  },
  "size": 2
}

Fetch a list of the user's recipient accounts. Use the profileId parameter to filter by the profile who created the accounts, you should do this based on the personal or business profile ID you have linked to your bank account. Other filters are listed below for your convenience, for example currency to filter the list shown when users select a recipient after choosing where they will send money by creating a quote.

Pagination

Pagination is supported for this endpoint. The response includes the seekPositionForNext and size parameters to manage this.

It works by setting size and seekPosition parameters in the call. Set the value in the seekPositionForNext of the previous response into the seekPosition parameter of your subsequent call in order to get the next page. To get the current page again, use the seekPositionForCurrent value.

Sorting

You can also set the sort parameter to control the sorting of the response, for example:

?sort=id,asc sort by id ascending.
?sort=id,desc sort by id descending.
?sort=currency,asc sort by currency ascending.

Request

GET https://api.sandbox.transferwise.tech/v2/accounts?profileId=<profileId>

All query parameters are optional.

Field Description Format
creatorId Creator of the account. Integer
profileId Filter by personal or business profile, returns only those owned by this profile. Defaults to the personal profile. Integer
currency Filter responses by currency, comma separated values are supported (e.g. USD,GBP). Text
active Filter by whether this profile is active. Defaults to true. Boolean
type Filter responses by account type, comma separated values are supported (e.g. iban,swiftCode). Text
fullName Search accounts by name, supports partial matches, but must contain those characters in that order. Text
ownedByCustomer Filter to get accounts owned by the customer or not, leave out to get all accounts. Text
size Page size of the response. Defaults to a maximum of 20. Integer
seekPosition Account ID to start the page of responses from in the response. null if no more pages. Integer
sort Sorting strategy for the response. Comma separated options: firstly either id or currency, followed by asc or desc for direction. Integer

Delete

Example Request:

curl -X DELETE https://api.sandbox.transferwise.tech/v2/accounts/{accountId} \
     -H "Authorization: Bearer <your api token>"

Deletes a recipient by changing its status to inactive. Only active recipients can be deleted and a recipient cannot be reactivated, however you can create a new recipient with the same details instead.

Response is empty if delete succeeds.

Requesting to delete a recipient that is already inactive will return an http status 403 (forbidden).

Request

DELETE https://api.sandbox.transferwise.tech/v2/accounts/{accountId}

Requirements

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v1/quotes/{quoteId}/account-requirements \
     -H "Authorization: Bearer <your api token>" 

Example Response:

[
  {
    "type": "aba",
     "title": "Local bank account",
     "fields": [
          {
            "name": "Legal type",
            "group": [
              {
                "key": "legalType",
                "type": "select",
                "refreshRequirementsOnChange": false,
                "required": true,
                "displayFormat": null,
                "example": "",
                "minLength": null,
                "maxLength": null,
                "validationRegexp": null,
                "validationAsync": null,
                "valuesAllowed": [
                  {
                    "key": "PRIVATE",
                    "name": "Private"
                  },
                  {
                    "key": "BUSINESS",
                    "name": "Business"
                  }
                ]
              }
            ]
          },
          {
            "name": "Routing Number",
            "group": [
              {
                "key": "abartn",
                "type": "text",
                "refreshRequirementsOnChange": false,
                "required": true,
                "displayFormat": null,
                "example": "111000025",
                "minLength": 9,
                "maxLength": 9,
                "validationRegexp": "\\d{9}",
                "validationAsync": {
                  "url": "https://test-restgw.transferwise.com/v1/validators/abartn",
                  "params": [
                    {
                      "key": "abartn",
                      "parameterName": "abartn",
                      "required": true
                    }
                  ]
                },
                "valuesAllowed": null
              }
            ]
          },
          {
            "name": "Account number",
            "group": [
              {
                "key": "accountNumber",
                "type": "text",
                "refreshRequirementsOnChange": false,
                "required": true,
                "displayFormat": null,
                "example": "12345678",
                "minLength": 4,
                "maxLength": null,
                "validationRegexp": "\\d{4,17}",
                "validationAsync": {
                  "url": "https://test-restgw.transferwise.com/v1/validators/aba-account-number",
                  "params": [
                    {
                      "key": "accountNumber",
                      "parameterName": "accountNumber",
                      "required": true
                    }
                  ]
                },
                "valuesAllowed": null
              }
            ]
          },
          {
            "name": "Account type",
            "group": [
              {
                "key": "accountType",
                "type": "radio",
                "refreshRequirementsOnChange": false,
                "required": true,
                "displayFormat": null,
                "example": "",
                "minLength": null,
                "maxLength": null,
                "validationRegexp": null,
                "validationAsync": null,
                "valuesAllowed": [
                  {
                    "key": "CHECKING",
                    "name": "Checking"
                  },
                  {
                    "key": "SAVINGS",
                    "name": "Savings"
                  }
                ]
              }
            ]
          },
          {
            "name": "Country",
            "group": [
              {
                "key": "address.country",
                "type": "select",
                "refreshRequirementsOnChange": true,
                "required": true,
                "displayFormat": null,
                "example": "Germany",
                "minLength": null,
                "maxLength": null,
                "validationRegexp": null,
                "validationAsync": null,
                "valuesAllowed": [
                  {
                    "key": "AX",
                    "name": "Åland Islands"
                  },
                  {
                    "key": "AL",
                    "name": "Albania"
                  },
                  {
                  ...
                  }
                ]
              }
            ]
          },
          {
            "name": "City",
            "group": [
              {
                "key": "address.city",
                "type": "text",
                "refreshRequirementsOnChange": false,
                "required": true,
                "displayFormat": null,
                "example": "London",
                "minLength": null,
                "maxLength": null,
                "validationRegexp": null,
                "validationAsync": null,
                "valuesAllowed": null
              }
            ]
          },
          {
            "name": "Postal code",
            "group": [
              {
                "key": "address.postCode",
                "type": "text",
                "refreshRequirementsOnChange": false,
                "required": true,
                "displayFormat": null,
                "example": "10025",
                "minLength": null,
                "maxLength": null,
                "validationRegexp": null,
                "validationAsync": null,
                "valuesAllowed": null
              }
            ]
          },
          {
            "name": "Address",
            "group": [
              {
                "key": "address.firstLine",
                "type": "text",
                "refreshRequirementsOnChange": false,
                "required": true,
                "displayFormat": null,
                "example": "50 Branson Ave",
                "minLength": null,
                "maxLength": null,
                "validationRegexp": null,
                "validationAsync": null,
                "valuesAllowed": null
              }
            ]
          }
        ]
    }
]

Request

GET https://api.sandbox.transferwise.tech/v1/quotes/{quoteId}/account-requirements
POST https://api.sandbox.transferwise.tech/v1/quotes/{quoteId}/account-requirements

The GET and POST account-requirements endpoints help you to figure out which fields are required to create a valid recipient for different currencies. You can use this data to build a dynamic user interface on top of these endpoints. This is a step-by-step guide on how these endpoints work.

Using account requirements

1.First create a quote to specify currencies and transfer amounts. See Create.Quote.

2.Call GET /v1/quotes/{quoteId}/account-requirements to get the list of fields you need to fill with values in the "details" section for creating a valid recipient account.

In order to create an "aba" recipient type you need these top level fields:

Some fields require multiple levels of fields in the details request, for example Country followed by State. This should be handled by the client based on the refreshRequirementsOnChange field. In the example above 'address.country' has this field set to true, indicating that there are additional fields required depending on the selected value. To manage this you should create a request with all of the initially requested data and call the POST account-requirements endpoint. You will be returned a response similar the previously returned data from GET account-requirements but with additional fields.

3.For example, construct a recipient object with all top level fields and call POST /v1/quotes/{quoteId}/account-requirements with these value to expose sub fields.
For example posting US as country will also add "state" to list of fields.

{
    "type": "aba",
    "details": {
      "legalType": "PRIVATE",
      "abartn": "111000025",
      "accountNumber": "12345678",
      "accountType": "CHECKING",
      "address": {
        "country": "US"
      }
    }
}

However, posting GB as country will not add any new fields as GB addresses do not have this extra requirement.

{
    "type": "aba",
    "details": {
      "legalType": "PRIVATE",
      "abartn": "111000025",
      "accountNumber": "12345678",
      "accountType": "CHECKING",
      "address": {
        "country": "GB"
      }
    }
}

It is possible that any new fields returned may also have refreshRequirementsOnChange field set to true. Therefore you must keep iterating on the partially created details object until POST account-requirements returns you no new fields that it previously didn't include in the response, you can do this by checking the size of the array returned.

4.Once you have built your full recipient details object you can use it to create a recipient.

For example this is a valid request to create a recipient with address in US Arizona:
POST /v1/accounts:

{
    "profile": your-profile-id,
    "accountHolderName": "John Smith",
    "currency": "USD",
    "type": "aba",
    "details": {
      "legalType": "PRIVATE",
      "abartn": "111000025",
      "accountNumber": "12345678",
      "accountType": "CHECKING",
      "address": {
            "country": "US",
        "state": "AZ"
        "city": "New York",
        "postCode": "10025",
        "firstLine": "45 Sunflower Ave"
      }
    }
}

We do not require the recipient's address for most receiving currencies and as such do not return these form elements by default. In some cases it may be desirable for you to collect this from users and store it as part of the recipient object in the TransferWise platform. If you wish to do this you can include the parameter &addressRequired=true in your call to GET /v1/quotes/{quoteId}/account-requirements, if this is present we will return address fields as part of the form.

Building a user interface

When requesting the form data from the account-requirements endpoint, the first level of the response defines different types of recipient you can create, the first thing to do is present the user a choice of which recipient type they wish to create, e.g. to GBP this could be local details or IBAN format. Each recipient type then has multiple fields describing the form elements required to be shown to collect information from the user. Each field will have a type value, these tell you the field type that your front end needs to render to be able to collect the data. A number of field types are permitted, these are:

type UI element
text A free text box
select A selection box/dialog
radio A radio button choice between options
date A text box with a date picker

Example data is also included in each field which should be shown to the user, along with a regex or min and mex length constraints that should be applied as field level validations. You can optionally implement the dynamic validation using the validationAsync field, however these checks will also be done when a completed recipient is submitted to POST /v1/accounts.

Response

Field Description Format
type "address" Text
fields[n].name Field description Text
fields[n].group[n].key Key is name of the field you should include in the JSON Text
fields[n].group[n].type Display type of field (e.g. text, select, etc) Text
fields[n].group[n].refreshRequirementsOnChange Tells you whether you should call POST account-requirements once the field value is set to discover required lower level fields. Boolean
fields[n].group[n].required Indicates if the field is mandatory or not Boolean
fields[n].group[n].displayFormat Display format pattern. Text
fields[n].group[n].example Example value. Text
fields[n].group[n].minLength Min valid length of field value. Integer
fields[n].group[n].maxLength Max valid length of field value. Integer
fields[n].group[n].validationRegexp Regexp validation pattern. Text
fields[n].group[n].validationAsync Validator URL and parameter name you should use when submitting the value for validation Text
fields[n].group[n].valuesAllowed[n].key List of allowed values. Value key Text
fields[n].group[n].valuesAllowed[n].name List of allowed values. Value name. Text

Transfers

Create

Example Request:

curl -X POST https://api.sandbox.transferwise.tech/v1/transfers \
     -H "Authorization: Bearer <your api token>" \
     -H "Content-Type: application/json" \
     -d '{ 
          "targetAccount": <recipient account id>,   
          "quoteUuid": <v2 quote id>,
          "customerTransactionId": "<the UUID you generated for the transfer attempt>",
          "details" : {
              "reference" : "to my friend",
              "transferPurpose": "verification.transfers.purpose.pay.bills",
              "sourceOfFunds": "verification.source.of.funds.other"
            } 
         }'

Example Response:

{
    "id": 468956,
    "user": <your user id>,
    "targetAccount": <recipient account id>,
    "sourceAccount": null,
    "quote": <quote id>,
    "status": "incoming_payment_waiting",
    "reference": "to my friend",
    "rate": 0.9065,
    "created": "2018-08-28 07:43:55",
    "business": <your business profile id>,
    "transferRequest": null,
    "details": {
        "reference": "to my friend"
    },
    "hasActiveIssues": false,
    "sourceCurrency": "EUR",
    "sourceValue": 661.89,
    "targetCurrency": "GBP",
    "targetValue": 600,
    "customerTransactionId": "bd244a95-dcf8-4c31-aac8-bf5e2f3e54c0"
}

Transfer is a payout order to recipient account based on a quote. Once created, a transfer needs to be funded within the next five working days. Otherwise, it will get automatically canceled.

Request

POST https://api.sandbox.transferwise.tech/v1/transfers

Field Description Format
targetAccount Recipient account id. You can create multiple transfers to same recipient account. Integer
quoteUuid V2 quote id. You can only create one transfer per one quote.
You cannot use same quote ID to create multiple transfers.
UUID
customerTransactionId This is required to perform idempotency check to avoid duplicate transfers in case of network failures or timeouts. UUID
details.reference (optional) Recipient will see this reference text in their bank statement. Maximum allowed characters depends on the currency route. Business Payments Tips article has a full list. Text
details.transferPurpose (conditionally required) For example when target currency is THB. See more about conditions at Transfers.Requirements Text
details.sourceOfFunds (conditionally required) For example when target currency is USD and transfer amount exceeds 10k. See more about conditions at Transfers.Requirements Text

There are two options to deal with conditionally required fields:

Response

You need to save transfer id for tracking its status later.

Field Description Format
id Transfer id Integer
user Your user id Integer
targetAccount Recipient account id Integer
sourceAccount Not used Integer
quote Quote id Integer
status Transfer current status Text
reference Deprecated, use details.reference instead Text
rate Exchange rate value Decimal
created Timestamp when transfer was created Timestamp
business Your business profile id
transferRequest Not used Integer
details.reference Payment reference text Text
hasActiveIssues Are there any pending issues which stop executing the transfer? Boolean
sourceCurrency Source currency code Text
sourceValue Transfer amount in source currency Decimal
targetCurrency Target currency code Text
targetValue Transfer amount in target currency Decimal
customerTransactionId UUID format unique identifier randomly generated per transfer request by the bank's backend UUID

Avoiding duplicate transfers

We use customerTransactionId field to avoid duplicate transfer requests. If your initial call to create a transfer fails (error or timeout) then you should retry the call using the same value in the customerTransactionId field that you used in the original call. This way we can treat subsequent retry messages as repeat messages and will not create duplicate transfers to your account should one have succeeded before. You should not retry indefinitely but use a sensible limit, perhaps with a back-off approach.

Cancel

Example Request:

curl -X PUT https://api.sandbox.transferwise.tech/v1/transfers/{transferId}/cancel \
     -H "Authorization: Bearer <your api token>" 

Example Response:

{
  "id": 16521632,
  "user": 4342275,
  "targetAccount": 8692237,
  "sourceAccount": null,
  "quote": 657171,
  "status": "cancelled",
  "reference": "reference text",
  "rate": 0.89,
  "created": "2017-11-24 10:47:49",
  "business": null,
  "transferRequest": null,
  "details": {
    "reference": "vambo 3"
  },
  "hasActiveIssues": false,
  "sourceCurrency": "EUR",
  "sourceValue": 0,
  "targetCurrency": "GBP",
  "targetValue": 150,
  "customerTransactionId": "54a6bc09-cef9-49a8-9041-f1f0c654cd88"
}

Only transfers which are not funded can be cancelled. Cancellation is final - it can not be undone.

Request

PUT https://api.sandbox.transferwise.tech/v1/transfers/{transferId}/cancel

Use transfer id that you obtained when creating a transfer.

Response

Field Description Format
id Transfer id Integer
user Your user id Integer
targetAccount Recipient account id Integer
sourceAccount Not used Integer
quote Quote id Integer
status Transfer current status Text
reference Deprecated, use details.reference instead Text
rate Exchange rate value Decimal
created Timestamp when transfer was created Timestamp
business Your business profile id
transferRequest Not used Integer
details.reference Payment reference text Text
hasActiveIssues Are there any pending issues which stop executing the transfer? Boolean
sourceCurrency Source currency code Text
sourceValue Transfer amount in source currency Decimal
targetCurrency Target currency code Text
targetValue Transfer amount in target currency Decimal
customerTransactionId UUID format unique identifier randomly generated per transfer request by the bank's backend UUID

Get by Id

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v1/transfers/{transferId} \
     -H "Authorization: Bearer <your api token>" 

Example Response:

{
  "id": 15574445,
  "user": 294205,
  "targetAccount": 7993919,
  "sourceAccount": null,
  "quote": 113379,
  "status": "incoming_payment_waiting",
  "reference": "good times",
  "rate": 1.2151,
  "created": "2017-03-14 15:25:51",
  "business": null,
  "transferRequest": null,
  "details": {
    "reference": "good times"
  },
  "hasActiveIssues": false,
  "sourceValue": 1000,
  "sourceCurrency": "EUR",
  "targetValue": 895.32,
  "targetCurrency": "GPB",
  "customerTransactionId": "6D9188CF-FA59-44C3-87A2-4506CE9C1EA3"
}

Get transfer info by id. Since we don't have push notifications yet, you can poll this endpoint to track your transfer status.

Request

GET https://api.sandbox.transferwise.tech/v1/transfers/{transferId}

Response

Field Description Format
id Transfer id Integer
user Your user id Integer
targetAccount Recipient account id Integer
sourceAccount Not used Integer
quote Quote id Integer
status Transfer current status Text
reference Deprecated, use details.reference instead Text
rate Exchange rate value Decimal
created Timestamp when transfer was created Timestamp
business Your business profile id
transferRequest Not used Integer
details.reference Payment reference text Text
hasActiveIssues Are there any pending issues which stop executing the transfer? Boolean
sourceCurrency Source currency code Text
sourceValue Transfer amount in source currency Decimal
targetCurrency Target currency code Text
targetValue Transfer amount in target currency Decimal
customerTransactionId UUID format unique identifier randomly generated per transfer request by the bank's backend UUID

Get Issues

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v1/transfers/{transferId}/issues \
     -H "Authorization: Bearer <your api token>" 

Example Response:

[
  {
    "type": "Payment has bounced back",
    "state": "OPENED",
    "description": "Incorrect recipient account number"
  }
]

Get pending issues that are suspending a transfer from further processing. This is more applicable for Bank Integrations use case when transfers are NOT funded from borderless account but funding is sent via bank transfer. For example "DEPOSIT_AMOUNT_LESS_INVOICE" means that arrived funding does not cover total transfer amount.

Request

GET https://api.sandbox.transferwise.tech/v1/transfers/{transferId}/issues

Response

Field Description Format
type Issue type:
  • DEPOSIT_AMOUNT_LESS_INVOICE
  • DEPOSIT_AMOUNT_MORE_INVOICE
  • PROVE_ACCOUNT_OWNERSHIP_WITH_REFERENCE_CODE
  • PROVE_ACCOUNT_OWNERSHIP_WITH_MICRO_DEPOSIT
  • JOINT_ACCOUNT_PROOF_NEEDED
  • BUSINESS_ORDER_PERSONAL_DEPO
  • INCORRECT_NAME_DEPOSIT
  • DEPOSIT_PROOF_NEEDED
  • PERSONAL_ORDER_BUSINESS_DEPO
  • INCORRECT_DEPOSIT_RECIPIENT_DETAILS
  • INCORRECT_SOURCE_ACCOUNT_NUMBER
    Text
    status Issue state: OPENED, IN_PROGRESS, CLOSED Text
    description Additional details about issue. For example 'Incorrect recipient account number' Text

    Get Delivery Time

    Example Request:

    curl -X GET https://api.sandbox.transferwise.tech/v1/delivery-estimates/{transferId} \
         -H "Authorization: Bearer <your api token>" 
    

    Example Response:

    {
       "estimatedDeliveryDate" : "2018-01-10T12:15:00.000+0000"
    }
    

    Get the live delivery estimate for a transfer by the transfer ID.
    The delivery estimate is the time at which we currently expect the transfer to arrive in the benificiary's bank account.
    This is not a guaranteed time but we are working hard to make these estimates as accurate as possible.

    Request

    GET https://api.sandbox.transferwise.tech/v1/delivery-estimates/{transferId}

    Response

    You need to save transfer id for tracking its status later.

    Field Description Format
    estimatedDeliveryDate Estimated time when funds will arrive to recipient's bank account Timestamp

    Get Receipt PDF

    Example Request:

    curl -X GET https://api.sandbox.transferwise.tech/v1/transfers/{transferId}/receipt.pdf \
         -H "Authorization: Bearer <your api token>" 
    

    Example Response:

    Receipt presented as application/pdf content-type
    

    Download transfer confirmation receipt in PDF format for transfers that are in status outgoing_payment_sent.

    Request

    GET https://api.sandbox.transferwise.tech/v1/transfers/{transferId}/receipt.pdf

    Response

    Transfer confirmation receipt in PDF format.

    List

    Example Request:

    curl -X GET https://api.sandbox.transferwise.tech/v1/transfers?offset=0&limit=100&profile=<your profile id>&status=funds_refunded&createdDateStart=2018-12-15&createdDateEnd=2018-12-30  \
         -H "Authorization: Bearer <your api token>" 
    

    Example Response:

    [
      {
        "id": 15574445,
        "user": 294205,
        "targetAccount": 7993919,
        "sourceAccount": null,
        "quote": 113379,
        "status": "funds_refunded",
        "reference": "good times",
        "rate": 1.1179,
        "created": "2018-12-16 15:25:51",
        "business": null,
        "transferRequest": null,
        "details": {
          "reference": "good times"
        },
        "hasActiveIssues": false,
        "sourceValue": 1000,
        "sourceCurrency": "EUR",
        "targetValue": 895.32,
        "targetCurrency": "GPB",
        "customerTransactionId": "6D9188CF-FA59-44C3-87A2-4506CE9C1EA3"
      },
      {
        "id": 14759252,
        "user": 294205,
        "targetAccount": 5570192,
        "sourceAccount": null,
        "quote": 113371,
        "status": "funds_refunded",
        "reference": "",
        "rate": 1.1179,
        "created": "2018-12-26 15:25:51",
        "business": null,
        "transferRequest": null,
        "details": {
          "reference": ""
        },
        "hasActiveIssues": false,
        "sourceValue": 1000,
        "sourceCurrency": "EUR",
        "targetValue": 895.32,
        "targetCurrency": "GPB",
        "customerTransactionId": "785C67AD-7E29-4DBC-9D4A-4C45D4D5333A"
      }
    ]
    

    Get the list of transfers for given user's profile (defaults to user's personal profile).

    You can add query parameters to specify user's profile (personal or business), time period and/or payment status.

    For example you can query:

    Request

    GET https://api.sandbox.transferwise.tech/v1/transfers/?offset=0&limit=100&profile=<your profile id>&status=funds_refunded&sourceCurrency=EUR&createdDateStart=2018-12-15T01:30:00.000Z&createdDateEnd=2018-12-30T01:30:00.000Z

    Field Description Format
    profile User profile id. If parameter is omitted, defaults to user's personal profile Integer
    status Status code or codes list (as comma separated value list) to filter returned transfers with. See Track transfer status for complete list of statuses. Text
    sourceCurrency Source currency code Text
    targetCurrency Target currency code Text
    createdDateStart Starting date to filter transfers, inclusive of the provided date. yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
    createdDateEnd Ending date to filter transfers, inclusive of the provided date. yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
    limit Maximum number of records to be returned in response Integer
    offset Starting record number Integer

    Response

    Field Description Format
    id Transfer id Integer
    user Your user id Integer
    targetAccount Recipient account id Integer
    sourceAccount Not used Integer
    quote Quote id Integer
    status Transfer current status Text
    reference Deprecated, use details.reference instead Text
    rate Exchange rate value Decimal
    created Timestamp when transfer was created Timestamp
    business Your business profile id
    transferRequest Not used Integer
    details.reference Payment reference text Text
    hasActiveIssues Are there any pending issues which stop executing the transfer? Boolean
    sourceCurrency Source currency code Text
    sourceValue Transfer amount in source currency Decimal
    targetCurrency Target currency code Text
    targetValue Transfer amount in target currency Decimal
    customerTransactionId UUID format unique identifier assinged by customer. Used for idempotency check purposes. UUID

    Requirements

    Example Request:

    curl -X POST https://api.sandbox.transferwise.tech/v1/transfer-requirements \
         -H "Authorization: Bearer <your api token>" \
         -H "Content-Type: application/json" \
         -d '{ 
                "targetAccount": <recipient account id>,
                "quoteUuid": <quote uuid>,
                "details": {
                  "reference": "good times",
                  "sourceOfFunds": "verification.source.of.funds.other",
                  "sourceOfFundsOther": "Trust funds"
                },
                "customerTransactionId": "6D9188CF-FA59-44C3-87A2-4506CE9C1EA3"
             }'
    

    Example Response:

    [
      {
        "type": "transfer",
        "fields": [
          {
            "name": "Transfer reference",
            "group": [
              {
                "key": "reference",
                "name": "Transfer reference",
                "type": "text",
                "refreshRequirementsOnChange": false,
                "required": false,
                "displayFormat": null,
                "example": null,
                "minLength": null,
                "maxLength": 10,
                "validationRegexp": null,
                "validationAsync": null,
                "valuesAllowed": null
              }
            ]
          },
          {
            "name": "Transfer purpose",
            "group": [
              {
                "key": "transferPurpose",
                "name": "Transfer purpose",
                "type": "select",
                "refreshRequirementsOnChange": true,
                "required": true,
                "displayFormat": null,
                "example": null,
                "minLength": null,
                "maxLength": null,
                "validationRegexp": null,
                "validationAsync": null,
                "valuesAllowed": [
                  {
                    "key": "verification.transfers.purpose.purchase.property",
                    "name": "Buying property abroad"
                  },
                  {
                    "key": "verification.transfers.purpose.pay.bills",
                    "name": "Rent or other property expenses"
                  },
                  {
                    "key": "verification.transfers.purpose.mortgage",
                    "name": "Mortgage payment"
                  },
                  {
                    "key": "verification.transfers.purpose.pay.tuition",
                    "name": "Tuition fees or studying expenses"
                  },
                  {
                    "key": "verification.transfers.purpose.send.to.family",
                    "name": "Sending money home to family"
                  },
                  {
                    "key": "verification.transfers.purpose.living.expenses",
                    "name": "General monthly living expenses"
                  },
                  {
                    "key": "verification.transfers.purpose.other",
                    "name": "Other"
                  }
                ]
              }
            ]
          },
          {
            "name": "Source of funds",
            "group": [
              {
                "key": "sourceOfFunds",
                "name": "Source of funds",
                "type": "select",
                "refreshRequirementsOnChange": true,
                "required": true,
                "displayFormat": null,
                "example": null,
                "minLength": null,
                "maxLength": null,
                "validationRegexp": null,
                "validationAsync": null,
                "valuesAllowed": [
                  {
                    "key": "verification.source.of.funds.salary",
                    "name": "Salary"
                  },
                  {
                    "key": "verification.source.of.funds.investment",
                    "name": "Investments (stocks, properties, etc.)"
                  },
                  {
                    "key": "verification.source.of.funds.inheritance",
                    "name": "Inheritance"
                  },
                  {
                    "key": "verification.source.of.funds.loan",
                    "name": "Loan"
                  },
                  {
                    "key": "verification.source.of.funds.other",
                    "name": "Other"
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
    

    Almost every country has their own specific originality when it comes to the nitty gritty details of domestic payment systems and money transfer regulations. Maximum allowed length of reference text is a good example. The US payment system, ACH, supports 10 characters only, but transfers within Mexico allow up to 100 characters and so on.

    Same is true for requirements arising from Anti-Money Laundering regulations adopted in different countries. Transfers from and to USD almost always require more details about source of funds and transfer purpose, compared to transfers to EUR or GBP.

    Endpoint /transfer-requirements exposes all these specific requirements based on specific quote and target recipient account.

    To make sure that processing of your transfers does not get delayed because of missing details, we highly recommend to verify the transfer requirements before before submitting any transfer.

    Request

    POST https://api.sandbox.transferwise.tech/v1/transfer-requirements

    1.Prepare request body to create transfer object first. Now post this request body to transfer-requirements endpoint to figure out if there are any other required fields.

    2.Analyze the returned list of fields. Our example includes reference, sourceOfFunds and transferPurpose fields. Field 'reference' is optional. Fields 'sourceOfFunds' and 'transferPurpose' are required and both have refreshRequirementsOnChange=true which indicates that there could be additional fields required depending on the selected value.

    In our example you will have to POST request to/v1/transfer-requirements` second time as well with values set for 'transferPurpose' and 'sourceOfFunds'. So in case you set sourceOfFunds = 'verification.source.of.funds.other' then another text field called "sourceOfFundsOther" is also required where you need to specify the details in free format.

    3.Once you get to the point where you have provided values for all fields which have refreshRequirementsOnChange=true then you have complete set of fields to compose a valid request to create a transfer object. For example this is a valid request to create a transfer.
    POST /v1/transfers:

    {
    "targetAccount": ,
    "quote": ,
    "details": {
    "reference": "good times",
    "sourceOfFunds": "verification.source.of.funds.other",
    "sourceOfFundsOther": "Trust funds"
    },
    "customerTransactionId": "6D9188CF-FA59-44C3-87A2-4506CE9C1EA3"
    }

    Response

    Field Description Format
    type "transfer" Text
    fields[n].name Field description Text
    fields[n].group[n].key Key is name of the field you should include in the JSON Text
    fields[n].group[n].name Field description Text
    fields[n].group[n].type Display type of field (e.g. text, select, etc) Text
    fields[n].group[n].refreshRequirementsOnChange Tells you whether you should call POST transfer-requirements once the field value is set to discover required lower level fields. Boolean
    fields[n].group[n].required Indicates if the field is mandatory or not Boolean
    fields[n].group[n].displayFormat Display format pattern. Text
    fields[n].group[n].example Example value. Text
    fields[n].group[n].minLength Min valid length of field value. Integer
    fields[n].group[n].maxLength Max valid length of field value. Integer
    fields[n].group[n].validationRegexp Regexp validation pattern. Text
    fields[n].group[n].validationAsync Validator URL and parameter name you should use when submitting the value for validation Text
    fields[n].group[n].valuesAllowed[n].key List of allowed values. Value key Text
    fields[n].group[n].valuesAllowed[n].name List of allowed values. Value name. Text




































    Simulation

    Simulate Transfer Processing

    Example Request:

    curl -X GET "https://api.sandbox.transferwise.tech/v1/simulation/transfers/{transferId}/processing" \
         -H "Authorization: Bearer <your api token>"
    

    Example Response:

    {
      "id": 15574445,
      "user": 294205,
      "targetAccount": 7993919,
      "sourceAccount": null,
      "quote": 113379,
      "status": "processing",
      "reference": "good times",
      "rate": 1.2151,
      "created": "2017-03-14 15:25:51",
      "business": null,
      "transferRequest": null,
      "details": {
        "reference": "good times"
      },
      "hasActiveIssues": false,
      "sourceValue": 1000,
      "sourceCurrency": "EUR",
      "targetValue": 895.32,
      "targetCurrency": "GPB"
    }
    

    You can simulate payment processing by changing transfer statuses using these endpoints.

    This feature is limited to sandbox only.

    Request

    GET https://api.sandbox.transferwise.tech/v1/simulation/transfers/{transferId}/processing

    Changes transfer status from incoming_payment_waiting to processing.

    GET https://api.sandbox.transferwise.tech/v1/simulation/transfers/{transferId}/funds_converted

    Changes transfer status from processing to funds_converted.

    GET https://api.sandbox.transferwise.tech/v1/simulation/transfers/{transferId}/outgoing_payment_sent

    Changes transfer status from funds_converted to outgoing_payment_sent.

    GET https://api.sandbox.transferwise.tech/v1/simulation/transfers/{transferId}/bounced_back

    Changes transfer status from outgoing_payment_sent to bounced_back.

    GET https://api.sandbox.transferwise.tech/v1/simulation/transfers/{transferId}/funds_refunded

    Changes transfer status from bounced_back to funds_refunded.

    Response

    Transfer entity with changed status.

    Application Webhooks

    Application webhook subscription is a mechanism that will allow you to receive notifications to your servers whenever various events happen in relation to different resources created by an application.

    Before proceeding, make sure the endpoint where you intend to receive webhooks satisfies the following requirements:

    https://webhooks.example.com/transfers-state-change is a valid URL; http://webhooks.example.com:8080/hook.php?type=transfers-state is not.

    You can have multiple subscriptions per event type though be mindful you will receive duplicate callbacks, one for each subscription. Find out more about webhook events here.

    Client token

    Request

    POST https://api.sandbox.transferwise.tech/oauth/token

    Use Basic Authentication with your api-client-id/api-client-secret as username/pwd and also use the header Content-Type: application/x-www-form-urlencoded.

    Field Description Format
    grant_type "client_credentials" Text

    Response

    Field Description Format
    access_token Access token to be used when creating an application subscription. Valid for 12 hours. uuid
    token_type "bearer" Text
    expires_in Expiry time in seconds Integer
    scope Text

    Create

    Example Request:

    curl -X POST "https://api.transferwise.com/v3/applications/{clientKey}/subscriptions" \
      -H "Authorization: Bearer <your client level token>" \
      -H "Content-Type: application/json" \
      -d '{
           "name": "Webhook Subscription #1",
           "trigger_on": "transfers#state-change",
           "delivery": {
             "version": "2.0.0",
             "url": "https://your.webhook.url/12345"
             }
          }'
    

    Example Response:

    {
        "id": "72195556-e5cb-495e-a010-b37a4f2a3043", 
        "name": "Webhook Subscription #1",
        "delivery": {
            "version": "2.0.0",
            "url": "https://your.webhook.url/12345" 
        },
        "trigger_on": "transfers#state-change", 
        "scope": {
            "domain": "application", 
            "id": "<your client key>"
        },
        "created_by": {
            "type": "application",
            "id": "<your client ID>", //clientId and key are not always the same
        },
        "created_at": "2019-10-10T13:55:57Z"
    }
    

    Request

    POST https://api.transferwise.com/v3/applications/{clientKey}/subscriptions

    {clientKey} can be received upon obtaining client credentials from our tech support.

    All fields listed below are required for creating a webhook subscription.

    Field Description Format
    name A custom name for your webhook to ease with identification Text
    trigger_on transfers#state-change Text
    delivery.version The event representation semantic version Text
    delivery.url Required. The URL where your server will be listening for events. Text

    Response

    Field Description Format
    id UUID that uniquely identifies the subscription Text
    name A custom name for your webhook to ease with identification Text
    trigger_on transfers#state-change Text
    delivery.version The event representation semantic version Text
    delivery.url The URL where your server will be listening for events. Text
    scope.domain Scope of this subscription, always "application" in this case Text
    scope.id Client key used to create this subscription Text
    created_by.type Creator type. Always application in this case Text
    created_by.id Client ID of the creator. Not always the same as the client key Text
    created_at Timestamp of when the subscription was created Text

    Delete

    Deletes a subscription by its identifier.

    Example Request:

    curl -X DELETE "https://api.transferwise.com/v3/applications/{clientKey}/subscriptions/{id}" \
      -H "Authorization: Bearer <your client level token>"
    

    Example Response:

    
    

    Request

    DELETE https://api.transferwise.com/v3/applications/{clientKey}/subscriptions/{id}

    Get by id

    Retrieves a subscription by its identifier.

    Example Request:

    curl -X GET "https://api.transferwise.com/v3/applications/{clientKey}/subscriptions/{id}" \
      -H "Authorization: Bearer <your client level token>"
    

    Example Response:

    {
        "id": "f215f353-35fd-405b-b27f-4fd603c905ed", 
        "name": "Webhook Subscription #1",
        "delivery": {
            "version": "2.0.0",
            "url": "https://your.webhook.url/12345" 
        },
        "trigger_on": "transfers#state-change", 
        "scope": {
            "domain": "application", 
            "id": "<your client key>"
        },
        "created_by": {
            "type": "application",
            "id": "<your client ID>", //clientId and key are not always the same
        },
        "created_at": "2008-09-15T15:53:00+00:00Z",
    }
    

    Request

    GET https://api.transferwise.com/v3/applications/{clientKey}/subscriptions/{id}

    List

    List all your subscriptions

    Example Request:

    curl -X GET "https://api.transferwise.com/v3/applications/{clientKey}/subscriptions" \
      -H "Authorization: Bearer <your client level token>"
    

    Example Response:

    [
      {
        "id": "e889e085-3677-4110-be26-3e9160ac9f25",
        "name": "#1 subscription",
        "delivery": {
          "version": "2.0.0",
          "url": "https://your.webhook.url/12345"
        },
        "trigger_on": "transfers#state-change",
        "created_by": {
          "type": "application",
          "id": "<your client ID>"
        },
        "scope": {
          "domain": "application",
          "id": "<your client key>"
        }
      },
      {
        "id": "eabeb3f5-c134-4a1c-99e2-86a1163daf1b",
        "name": "#2 subscription",
        "delivery": {
          "version": "2.0.0",
          "url": "https://your.webhook.url/12345"
        },
        "trigger_on": "transfers#state-change",
        "created_by": {
          "type": "application",
          "id": "<your client ID>"
        },
        "scope": {
          "domain": "application",
          "id": "<your client key>"
        }
      }
    ]
    

    Request

    GET https://api.transferwise.com/v3/applications/{clientKey}/subscriptions

    Webhook events

    Events are messages that will be sent to your server as HTTP POST requests once you create a webhook subscription (and a resource you have access to is updated). They will not contain any personally identifiable information.

    To acknowledge that you have successfully processed an event, make sure your server answers with the HTTP status code 200 within 5s. Otherwise, we will consider the delivery attempt as having failed and will later try to resend the message.

    We will attempt to redeliver messages at increasing intervals over a two week period. We will try at most 25 times to do this.

    Signature header

    TransferWise public key for production environment:

    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvO8vXV+JksBzZAY6GhSO
    XdoTCfhXaaiZ+qAbtaDBiu2AGkGVpmEygFmWP4Li9m5+Ni85BhVvZOodM9epgW3F
    bA5Q1SexvAF1PPjX4JpMstak/QhAgl1qMSqEevL8cmUeTgcMuVWCJmlge9h7B1CS
    D4rtlimGZozG39rUBDg6Qt2K+P4wBfLblL0k4C4YUdLnpGYEDIth+i8XsRpFlogx
    CAFyH9+knYsDbR43UJ9shtc42Ybd40Afihj8KnYKXzchyQ42aC8aZ/h5hyZ28yVy
    Oj3Vos0VdBIs/gAyJ/4yyQFCXYte64I7ssrlbGRaco4nKF3HmaNhxwyKyJafz19e
    HwIDAQAB
    

    How to verify signatures (in Java):

    public boolean verifySignature(String encodedPublicKey, String signature, String payload) {
      X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getMimeDecoder().decode(encodedPublicKey));
      KeyFactory keyFactory = KeyFactory.getInstance("RSA");
      PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
    
      Signature sign = Signature.getInstance("SHA1WithRSA");
      sign.initVerify(publicKey);
      sign.update(payload.getBytes());
    
      byte[] signatureBytes = Base64.getDecoder().decode(signature);
    
      return sign.verify(signatureBytes);
    }
    

    Each outgoing webhook request is signed. Whilst event payloads do not contain any sensitive information, you may want to verify if the request is coming from TransferWise (however this is optional). We advise you not to process any requests where signature appears to be forged.

    Each POST request includes X-Signature header, which contains a signature.

    Event payload

    Basic event payload:

    {
      "data": {},
      "subscription_id": "db463333-3333-3333-3333-185d1ee81585",
      "event_type": "...",
      "schema_version": "2.0.0",
      "sent_at": "2019-10-14T12:43:37Z"
    }
    

    Event payload

    All events share same payload structure. Depending on the event_type the only object that will change is data.

    Field Description Format
    data Object with information about updated resource Object
    subscription_id ID of the subscription that triggered the event UUID
    event_type Type of event, which defines data object Integer
    schema_version The event representation semantic version String
    sent_at Timestamp when update happened Timestamp

    Transfer status change event

    Example event:

    {
      "data": {
        "resource": {
          "id": 99330022,
          "profile_id": 11121314,
          "account_id": 1514131211,
          "type": "transfer"
        },
        "current_state": "processing",
        "previous_state": "incoming_payment_waiting",
        "occurred_at": "2019-10-14T12:43:37Z"
      },
      "subscription_id": "db463333-3333-3333-3333-185d1ee81585",
      "event_type": "transfers#state-change",
      "schema_version": "2.0.0",
      "sent_at": "2019-10-14T12:43:37Z"
    }
    

    Event

    Events will be triggered every time transfer status is updated.

    Keep in mind that we do not guarantee the order of when events are sent, so you may get an older update after the most recent one.

    Please use the data.occurred_at field to reconcile the order.

    If you would like to subscribe to transfer state change events, please use transfers#state-change when creating your subscription.

    To see how you can simulate transfer status changes, please see Simulate Transfer Processing.

    Field Description Format
    data.resource.id ID of the transfer that got updated String
    data.resource.profile_id ID of the profile that owns the transfer Integer
    data.resourceI.account_id ID of transfer's recipient Integer
    data.resource.type Type of the resource that was updated String
    data.current_state Newly acquired state of the resource, possible values are same as transfer statuses String
    data.previous_state Previous state of the resource, possible values are same as transfer statuses String
    data.occured_at Timestamp when the update happened Timestamp







































    Comparison

    Request comparison quotes

    Example Request: shell curl -X GET https://api.transferwise.com/v3/comparisons/?sourceCurrency=GBP&targetCurrency=EUR&sendAmount=10000

    Example Response: json { "sourceCurrency": "GBP", "targetCurrency": "EUR", "sourceCountry": null, "targetCountry": null, "providerCountry": null, "providerType": null, "sendAmount": 10000.0, "providers": [ { "id": 39, "alias": "transferwise", "name": "TransferWise", "logo": "https://dq8dwmysp7hk1.cloudfront.net/logos/transferwise.svg", "type": "moneyTransferProvider", "partner": false, "quotes": [ { "rate": 1.15989, "fee": 37.12, "receivedAmount": 11555.84, "dateCollected": "2019-10-22T14:36:43Z", "sourceCountry": null, "targetCountry": null, "markup": 0.0, "deliveryEstimation": { "duration": { "min": "PT20H8M16.305111S", "max": "PT20H8M16.305111S" }, "providerGivesEstimate": true } } ] }, { "id": 1, "alias": "barclays", "name": "Barclays", "logo": "https://dq8dwmysp7hk1.cloudfront.net/logos/barclays.svg", "type": "bank", "partner": false, "quotes": [ { "rate": 1.12792426, "fee": 0.0, "receivedAmount": 11279.24, "dateCollected": "2019-10-22T14:00:04Z", "sourceCountry": "GB", "targetCountry": "ES", "markup": 2.75592858, "deliveryEstimation": { "duration": { "min": "PT24H", "max": "PT24H" }, "providerGivesEstimate": true } }, ... { "rate": 1.12792426, "fee": 0.0, "receivedAmount": 11279.24, "dateCollected": "2019-10-22T14:00:04Z", "sourceCountry": "GB", "targetCountry": "FI", "markup": 2.75592858, "deliveryEstimation": { "duration": { "min": "PT24H", "max": "PT24H" }, "providerGivesEstimate": true }, ... } ... ] } ] }

    The comparison API can be used to request price and speed information about various money transfer providers. This includes not only TransferWise but other providers in the market.

    Price Estimation

    The quotes (price / speed) provided by this API are based off of real quotes collected from 3rd party websites. We collect both the advertised exchange rate and fee for each provider for various amounts. When a comparison is requested we calculate the markup percentage on the collected exchange rate on the mid-market rate at the time of collection, we then apply this markup % on the current mid-market rate to provide a realistic estimate of what each provider offers. We try to collect data for all providers once per hour to ensure we provide as accurate and up to date information as possible, although our attempts do not always succeed.

    Note: Today, we only provide estimations for FX transactions with a Bank Transfer pay-in / pay-out option. This is important to stress as many providers offer significantly different fees / exchange rates when used debit / credit card, cash etc.

    For more details on the data collection process please see the following page:

    https://transferwise.com/gb/compare/disclaimer

    If you have questions or suspect any data to be inaccurate or incomplete please contact us at:

    comparison@transferwise.com

    Delivery Estimation

    Similar to price, we collect speed data for most (if not all) providers which we have price information for. Many providers display speed estimates to their customers in a number of different ways.

    Some examples:

    The below API intends to model these in a consistent format by providing a min / max range for all delivery estimations. An estimate that states "up to X" will have "max" set to a duration but "min" as null, a "from X" will have "min" set to a duration and "max" as null. Finally for those providers who offer a specific, point in time estimation (like TransferWise), the API will surface a duration where min/max are equal.

    Quotes structure

    In order to provide the most flexible and accurate data for clients, we surface a denormalised list of quotes per provider where each quote represents a unique collection of comparison "dimensions".

    A single given provider may expose multiple quotes for the same currency route. The most common example is where a provider offers different pricing for one country vs another country which uses the same currency. e.g:

    Provider X:

    The same principle applies for speed. I.e a provider may have different speed estimates for different target countries and hence we expose these as discrete quotes - where a quote is a unique combination of route / country / speed / price factors.

    A client may choose to reduce this set of quotes down to a single or several quotes in order to display a relevant quote to a given user. An example where we take the cheapest quote for a given currency route (and also surface the target country) can be seen at the below link:

    https://transferwise.com/gb/compare/?sourceCurrency=GBP&targetCurrency=EUR&sendAmount=1000

    Request

    GET https://api.transferwise.com/v3/comparisons/?sourceCurrency=GBP&targetCurrency=EUR&sendAmount=10000

    Field (Query Param) Description Format
    sourceCurrency ISO 4217 source currency code Text
    targetCurrency ISO 4217 target currency code Text
    sendAmount Amount in source currency Decimal
    sourceCountry (Optional) Filter by source country (ISO 3166-1 Alpha-2 code) Text
    targetCountry (Optional) Filter by target country (ISO 3166-1 Alpha-2 code) Text
    providerType (Optional) Filter by provider type One of "bank","moneyTransferProvider"

    Response

    Field Description Format
    id Provider id Integer
    alias Provider alias (lowercase slug name) Text
    name Provider name (presentational / formal name) Text
    logo URL pointing to provider logo (default svg format) Text
    type Provider type Text
    partner Whether a partner of TransferWise or not Boolean
    quotes An array of estimated quotes per provider Array
    quotes.rate The live estimated exchange for the provider for this quote Timestamp
    quotes.fee The estimated fee for the provider for this quote Integer
    quotes.receivedAmount The total estimated receive amount for the provider for this quote Integer
    quotes.dateCollected The date of collection for the original quote Text
    quotes.sourceCountry source country (ISO 3166-1 Alpha-2 code) Timestamp
    quotes.targetCountry target country (ISO 3166-1 Alpha-2 code) Decimal
    quotes.deliveryEstimation Delivery estimation details - i.e a speed estimate Object
    quotes.deliveryEstimation.duration Duration range Object
    quotes.deliveryEstimation.duration.min Minimum quoted time for transaction delivery ISO 8601 duration format
    quotes.deliveryEstimation.duration.max Maximum quoted time for transaction delivery ISO 8601 duration format
    quotes.deliveryEstimation.providerGivesEstimate Whether a provider publicly surfaces / exposes a speed estimate Boolean

    Terms and Conditions

    Get Terms and Conditions

    Example Request:

    curl -X GET "https://api.sandbox.transferwise.tech/v1/terms/default"
    

    Example Response:

    <h2><strong>1. How to read this Agreement</strong></h2>
    <p>This Agreement contains 30 sections. You may go directly to any section by selecting the appropriate link provided. The headings are for reference only. Some capitalised terms have specific definitions in section [3]. Underlined words in this Agreement contain hyperlinks to further information.</p>
    <h2><strong>2. Why you should read this Agreement</strong></h2>
    <p>2.1 What this Agreement cover. These are the term and conditions on which we provide our Services to you.</p>
    <p>2.2 Why you should read them. Please read this Agreement carefully before you start to use our Services. This Agreement (always together with the documents referred to in it) tell you who we are, how we will provide the Services to you, how this Agreement may be changed or ended, what to do if there is a problem and other important information. If you think that there is a mistake in this Agreement or require any changes, please <u>contact us</u> to discuss.</p>
    <p>2.3 Other additional documents which applies to you. This Agreement refers to the following additional documents, which also apply to your use of our Services:</p>
    <ul><li>(a) <u>Our Privacy Policy</u>, which sets out the terms on which we process any personal data we collect about you, or that you provide to us. By using our Services, you consent to such processing and you promise that all data provided by you is accurate.</li>
    <li>(b) <u>Our Cookie Policy</u>, which sets out information about the “cookies” on our Website.</li>
    ...
    

    Get TransferWise terms and conditions in HTML format to show to your customers who are signing up for their TransferWise account.

    Request

    GET https://api.sandbox.transferwise.tech/v1/terms/{clientId}

    Use "default" as clientId to fetch TransferWise general terms and conditions.

    No authentication is required for this endpoint.

    Response

    Terms and conditions in HTML format.

    Language Support

    Internationalisation support for translation of strings returned by the API is supported for the following endpoints:

    Endpoint
    /v1/quotes
    /v1/quotes/<quoteId>/account-requirements
    /v1/accounts
    /v1/transfers
    /v1/transfer-requirements

    When calling these endpoints if you include an Accept-Language header with a supported language code as the value then stings will be returned in the requested language. The languages supported by TransferWise are:

    Language Code
    American English en_US
    British English en
    Dutch nl
    French fr
    German de
    Hungarian hu
    Italian it
    Japanese ja
    Korean ko
    Polish pl
    Portuguese pt
    Romanian ro
    Russian ru
    Spanish es

    If you request an unsupported language then British English will be returned by default.

    Errors

    HTTP Status Codes

    We use common HTTP status codes included in the response header to indicate success or failure.

    Code Description
    200 OK. Successful request.
    201 OK. Resource created.
    400 Bad request. Request message data did not pass validation.
    401 Unauthorised. Not authorised to access requested data.
    403 Forbidden. Access to requested data is forbidden.
    404 Not Found. Requested resource does not exist.
    408 Timeout. Operation timed out.
    422 Unprocessable entity. Request message data did not pass validation.
    500 TransferWise server error.

    Validation Errors

    Example Validation Error:

    {
        "errors": [
            {
                "code": "error.route.not.supported",
                "message": "This route is not supported",
                "arguments": [
                    "CNY-EUR"
                ]
            }
        ]
    }
    

    Data validation or violation of business rules related errors. Response could contain multiple errors.

    Authentication Errors

    Example Authentication Error:

    {
        "error": "unauthorized",
        "error_description": "Full authentication is required to access this resource"
    }
    

    Security related errors.

    System Errors

    Example System Error:

    {
      "timestamp": "2017-02-02T13:07:39.644+0000",
      "status": 500,
      "error": "Internal Server Error",
      "exception": "java.lang.NullPointerException",
      "message": "No message available",
      "path": "/v1/quotes/106031/account-requirements"
    }
    

    Something went wrong in our side.