Wise Platform API

Base URL Sandbox

https://api.sandbox.transferwise.tech

Base URL LIVE

https://api.transferwise.com

Welcome to the Wise Platform API documentation. You can explore the different ways to use our API and choose the right one for you below.

Payouts and Account Automation

This lets you to automate how you use your Wise account. You can automate payments, connect your business tools, and create ways to manage your finances.

You can:

  • Power your cross-border and domestic payouts with a single API integration.
  • Pay out directly to bank accounts or email recipients.
  • Monitor payments received to your Wise local bank details (AUD, EUR, GBP, NZD, USD, PLN).
  • Get statements for balance reconciliation and accounting purposes.
  • Fully automate transfer creation and track statuses.
  • Always get the mid-market exchange and our low cost transparent fees.
  • Use our platform to create and build your own tool to manage your finances.

Our Payouts Guide will help you get started with the technical integration.

Third-Party Payouts

Third-Party Payouts allows marketplaces and financial institutions (banks and payment service providers) to use Wise as a payout option for their customers. It’s different from Payouts since it doesn’t require your company to be the originator of payments. Instead, Wise will act as a third-party to your customers when they initiate a payment through your site.

All the above listed payouts and account automation benefits are also true for third-party payouts service. You can build payment services to your customers on top of Wise payment platform that enables your customers to send cross-border payouts to 40+ currencies in 70+ countries.

In addition there will also be a dedicated account manager who will be your primary contact to solve all questions and support issues should these arise.

Please note that subscribing to third party payouts service requires your company to complete enhanced due diligence process performed by Wise compliance team. Please contact our sales team for more info how to get started.

Our Third-Party Payouts Guide will help you get started with the technical integration.

Banks

Our bank integration lets banks build Wise payments seamlessly into their own desktop and mobile apps. Banks can also build their own native user experience directly onto our API, co-branded with Wise.

What are the benefits for my bank?

  • Provide your customers access to some of the fastest and cheapest cross-border payments available to consumers and businesses today.
  • Offer competitive, fair, and transparent pricing to customers at the mid-market exchange rate.
  • Reduce your operational costs of cross-border payments.
  • Stop losing out on cross-border revenues because your customers are finding better alternatives.

How does it work?

  • Transparent and fair pricing - Your customers will get the same price no matter if they make transfers via your bank integration or directly via Wise.
  • Same great Wise service - Your customers get access to our 24/7 customer support.
  • Custom solution - We’ll work together to find and build a solution that works for your bank. There’s no one-size-fits-all approach. Together we’ll decide:
    • How do we set up flow of funds?
    • How do we handle customer support?
    • How do we harmonise customer onboarding and AML processes?

See what some of our bank partners have to say


An example native user experience based on the Wise Platform API Example native user experience

Please contact banks@wise.com to get started.

Take a look at our technical integration here – Bank Integration Guide.

Affiliates

When you apply to the Wise affiliates program you can get access to our API to help you build your own valuable content for your customers or readers.

The Wise Platform API lets you to:

  • Get the real-time mid-market exchange rates for any currency route.
  • Get up to 30 days of historical mid-market exchange rates for any currency route.
  • Get a Wise quote for any supported currency route, which includes our fees and estimated delivery time.

The Affiliates Integration Guide helps you get started with the technical integration.

Connected Applications

With Connected Applications, you can let your customers connect their Wise accounts to your product. Say you’re an accounting software – doing this could let your customers automate reconciliation. If you’re a payroll company, you could push customer payments right into Wise. You could even push Wise notifications through your app. Whatever you want to build, you likely could!

We need to take a deeper look into your application use case and the added value it will bring to our joint customers in order to authorise such an integration. So before starting the technical work please contact our sales team for more info on how to get started.

Our Connected Apps Guide gives you an overview of required technical integration work.

Receive Money

You can receive money to the local bank details that come with your Wise account (USD, EUR, GBP, AUD, NZD and PLN) and reconcile these incoming payments via the API.

You’re also able to create a webhook subscription to receive event callbacks to your server when payments are received. Here’s more information about the webhooks.

Please note that we don't send any information over webhook calls that might contain personally identifiable information (PII) about the sender (including the payment reference).

To reconcile incoming payments you might also need to match the information received via webhooks with the information that can be obtained from the statements.

Checkout flows

We currently don’t offer the option to build Wise into your checkout flow as a payment option to receive money. Note though that Wise can be added as a payout option on your site for beneficiaries to choose to receive their payout through to an email address, directly to a bank account or any other mechanism we support in our standard product.

Open Banking

Under the Second Payment Services Directive (PDS2) we are opening up the standardized version of our API to the rest of the world. Find out more about our Open Banking API

Payouts Guide

Welcome to the Wise payouts API documentation. Before you start coding, please take few moments to review some important information about Wise and our API.

Getting started

1. Learn about Wise.

Wise and its borderless account features and pricing are best explained below.

https://wise.com/multi-currency-account/pricing

2. Sign up for your Wise account, activate your borderless account, and complete verification.

Using the product before integrating with our API will help you understand how our payment flow works. Just follow these four steps.

  • Sign up for your Wise account https://wise.com/multi-currency-account.

  • Complete verification – you need to do this before you start your technical integration. Also ensure you’re compliant with our Terms and Conditions and Acceptable Use Policy. Also make sure two-step log in is set up.

  • Activate at least one currency in your borderless account, deposit small amount (via card or bank transfer) and setup your first payment. This penny-testing is not mandatory of course, but we do recommended it so you will understand how Wise payment flow works.

  • Verify that our coverage includes your currency route(s). Check Supported Currencies. Please note that there are few restrictions for businesses, please review Restricted Business Routes

  • Please note that our Fixed Rate functionality is intended to provide time for customers to send funds to Wise, while holding the rate for them. Wise is not a trading platform and the Fixed Rate functionality is automatically disabled if abusive behaviour (such as multiple transfer creation and selective completion) is detected.

3. Choose the best tool for you

You don’t necessarily need to integrate with the API to make a large number of payouts. We have two ways you can do it:

  • Batch payments. Create and send up to 1,000 transfers with just one payment using our Batch Payments tool. All you need to do is fill a CSV file with all the transfer details, upload it to Wise, and pay for the batch. No development effort needed.

  • API integration. Completely automate your payment process by sending payment orders via the Wise Platform API.

API access

curl -X GET https://api.sandbox.transferwise.tech/v1/profiles \
     -H "Authorization: Bearer xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"

Authentication

Sign up for a developer account and get your personal API token for our sandbox. https://sandbox.transferwise.tech/register

NB! Two factor authentication (2FA) code for sandbox login is 111111.

Your developer account will have some test money that you can use to start making payments in same way as you would in a live environment. You can get your API tokens in the Settings tab of your account page.

Add your API token as header parameter to every request like this:

Authorization: Bearer xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx

Acquiring your API token

Your API tokens section can be found at the bottom of the Settings page inside your Wise account. By default, you have no active tokens. You can issue new tokens after enabling 2-step login.

We support tokens of two permission levels:

  • Read only - List and show transfers, recipients and balances
  • Full access - Create, manage and fund transfers

Issue a Read only token unless you specifically need the capabilities of Full access. Token permission level can be changed after issuance. The lifetime of the token is 10 years.

Keeping your API token safe

Your API tokens should be guarded closely. They represent your identity and authorization and can be used to interact with your Wise account on your behalf. Whoever has access to your token can access your account details and history. In the case of a Full access token, they can also send transfers. Once you obtain an API token from us, it is on you to keep it safe.

Below is technical advise and guidance on how to protect your tokens. Not everything may apply to the application you are building and the goal is not to provide a long checklist of things to do. Rather, we attempt to provide generic guidance and best-practices, to send you in the right direction. You will have to do additional research and consider the specific technology and purpose of your application.

Source code

Don't store API tokens as plaintext files in Git

$ git clone https://github.com/mycompany/myapp.git
$ cat myapp.git/apiconfig.json
{
  "token": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx",
  "url": "api.transferwise.com"
}

A common mistake made by engineers is storing access tokens in source code, in plaintext - which is then shared in a version control system, sometimes publicly.

When an API token is stored like this, it can be accessed and used by anyone who has access to the source code. Avoid storing secrets in code.

Instead:

  • Use environment variables to pass secrets into your application. You can configure them in your web server settings, startup script or platform-specific tools such as Docker or Kubernetes.
  • If your deployment platform has a dedicated mechanism for storing secrets, use it
  • Use a configuration file that is excluded from your version control. It can be created manually, or put into the deployment server by automated tools. Make sure the file can only be read by your web application

Limit permissions of a sensitive configuration file

$ cp .env.sample .env
$ echo .env >> .gitignore
$ chown myapp:root .env && chmod 600 .env

Token lifecycle

If you suspect that your token has leaked, revoke and rotate it. If you accidentally push a token to a remote public repository, rotate it. Quickly deleting an access token from VCS might not be enough - remember that VCS stores historical changes, is distributed and might have automation assigned to new pushes.

Revoke old tokens that you no longer need or use.

During the lifetime of an active token, limit the amount of people and systems who can access it. E-mail inboxes and chat logs are archived and not a secure place to hold tokens. Ideally, your access token would live only in Wise systems and your production system(s) that actually need it. You do not need to hold a backup copy of the token, as you can reveal an existing token from your profile settings page.

Encryption

Wise Platform API is using HTTPS with >=TLS 1.2. Non-encrypted HTTP connections are not accepted. Do not connect to our API with unencrypted HTTP, as this will transmit your access token in plaintext over the network.

Verifying certificates in client code

<?php
// Secure - this will fail when an invalid HTTPS certificate is returned.
// Such failure is not normal and most likely means there is something
// in-between you and Wise, intercepting communications.
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_URL, 'https://api.transferwise.com');


// Insecure - do not do this. This will not validate certificates and
// might leak your access token to an attacker.
// See https://curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYPEER.html
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_URL, 'https://api.transferwise.com');

Validate certificates. You should not proceed with a connection when you receive a certificate validation error from Wise. Make sure all parts of your application are using encryption and HTTPS and failing when certificate validation fails.

Application design

Secure your application against common security flaws (OWASP Top 10). Think how an attacker could leverage Unrestricted File Upload or Insecure Direct Object Reference to read the contents of your server's environment or config files.

If your application is larger, consider extracting Wise-specific functionality into a separate middleware or service layer. This would enable you to move API tokens there, separate from the main application.

Do not store the token in user-accessible code such as browser-side JavaScript or Android apps that can be decompiled. The token should always live server-side, exposing domain-logic via API-s.

If you need to pass the token around via HTTP requests, use HTTP headers or POST body - do not store the token in URI or query parameters. Web servers usually log the URL and browsers pass it between websites via the Referrer header.

Limiting token access by IP

You can enhance your integration security by only allowing certain IP addresses to use your API token.

Typically, you would integrate with our API from a set number of fixed IP addresses. Restricting access from all other IPs will make it harder to misuse your API token, should it ever leak. IP whitelisting does not protect against cases where several clients egress from the same whitelisted IP (shared external IP for the office network, an egress proxy in front of all of your servers).

Each token can be limited to single IP addresses, a set of IP addresses or entire IP ranges. You can do this in the API token edit view.

Please note:

  • IP addresses should use only IPv4 format e.g. 192.168.100.14
  • IP ranges should use CIDR notation e.g. 192.168.100.0/24 which would include 192.168.100.0 up to 192.168.100.255
  • You can authorize multiple discrete IP-s or IP ranges for one token

If a request is being made using an IP address that is not in the whitelisted IP addresses, the server will respond with a 401 Unauthorized HTTP status code.

Testing

By default in our sandbox environment strong customer authentication is disabled. You can enable it for your account on the public keys management page.

The option for toggling the check yourself will also be available in production as long as it is optional.

TEST and LIVE environments

Please note Sandbox environment is limited. We do not send any emails from it as well as transfer processing is not simulated. Please consider Simulation endpoints to change transfer state after funding.

Get your profile id

Example Request:

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

Example Response:

[
  {
    "id": 217896,
    "type": "personal",
    "details": {
      "firstName": "Oliver",
      "lastName": "Wilson",
      "dateOfBirth": "1977-07-01",
      "phoneNumber": "+3725064992",
      "avatar": "https://lh6.googleusercontent.com/-XzeFZ2PJE1A/AAAAAAAI/AAAAAAAAAAA/RvuvhXFsqs0/photo.jpg",
      "occupation": null,
      "primaryAddress": 236532
    }
  },
  {
    "id": 220192,
    "type": "business",
    "details": {
      "name": "ABC Logistics Ltd",
      "registrationNumber": "12144939",
      "acn": null,
      "abn": null,
      "arbn": null,
      "companyType": "LIMITED",
      "companyRole": "OWNER",
      "descriptionOfBusiness": "Information and communication",
      "primaryAddress": 240402,
      "webpage": "https://abc-logistics.com"
    }
  }
]

You only need to call this endpoint once to obtain your user profile id. Your personal and business profiles have different IDs. Profile id values are required when making payouts.

It’s recommended to always provide profileId when you’re creating new resources later (Create Quote, Create Recipient Account, Create Transfer). If you omit profileId then resource will by default belong to your personal profile. This might not be your intention, as you most probably want to execute transfers under your business profile.

Request

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

Response

Personal Profile Fields

Field Description Format
id Personal profile id Integer
type Profile type Text
details.firstName Person first name Text
details.lastName Person last name Text
details.dateOfBirth Date of birth "yyyy-mm-dd"
details.phoneNumber Phone number Text
details.avatar Link to avatar image Text
details.occupation Occupation Text
details.primaryAddress Address object id Integer

Business Profile Fields

Field Description Format
id Business profile id Integer
type Profile type Text
details.name Business name Text
details.registrationNumber Business registration number Text
details.acn ACN (only applicable for Australian business) Text
details.abn ABN (only applicable for Australian business) Text
details.arbn ARBN (only applicable for Australian business) Text
details.companyType Company legal type Text
details.companyRole Person's role in the company Text
details.descriptionOfBusiness Business description Text
details.primaryAddress Address object id Integer
details.webpage Webpage URL Text

Create quote

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"
    }]
}

There are four steps to execute payouts:

Step 1: Create a quote

Step 2: Create a recipient account

Step 3: Create a transfer

Step 4: Fund a transfer

Quote fetches current mid-market exchange rate that will be used for your transfer. Quote also calculates our fee and estimated delivery time.

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
targetAccount Optional. If provided can be used as an alternative to updating the quote. Integer

Response

The payOut field is used to select the correct entry in the paymentOptions array in order to know which fees to display to your customer. Find the paymentOption that matches the payOut field shown at the top level of the quote resource and payIn based on the settlement model the bank is using. By default this is BANK_TRANSFER, unless you are using a prefunded or bulk settlement model.

When showing the price of a transfer, always show the total fees of a payment option.

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 received. Decimal
payOut Mechanism we use 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. See above for help on choosing the correct one to display. [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

Create recipient account

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>, 
          "accountHolderName": "Ann Johnson",
          "legalType": "PRIVATE",
           "details": { 
              "sortCode": "231470", 
              "accountNumber": "28821822" 
           } 
         }'

Example Response (Create GBP recipient):

{
    "id": 31273058,
    "profile": <your profile id>, 
    "accountHolderName": "Ann Johnson",
    "type": "sort_code", 
    "country": "GB", 
    "currency": "GBP",
    "details": {
        "accountNumber": "28821822",
        "sortCode": "231470"
    }
}

There are four steps to execute payouts:

Step 1: Create a quote

Step 2: Create a recipient account

Step 3: Create a transfer

Step 4: Fund a transfer

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

Recipient bank account details are different for different currencies. For example, you only need to know the IBAN number to send payments to most European and Nordic countries. But in order to send money to Canada, you’d need to fill out four fields: You recipient’s institution number, transit number, account number, and account type.

A UK GBP example is provided here. You can find other currency examples in Recipient Accounts section below.

Request

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

Field Description Format
currency 3 character currency code Text
type Recipient type Text
profile Personal or business profile id Integer
accountHolderName Recipient full name Text
legalType Recipient legal type: PRIVATE or BUSINESS Text
details Currency specific fields Group
details.sortCode Recipient bank sort code (GBP example) Text
details.accountNumber Recipient bank account no (GBP example) Text

Response

Recipient id is needed for creating transfers in step 3.

Field Description Format
id recipientAccountId 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
details Currency specific fields Group
details.sortCode Recipient bank sort code (GBP example) Text
details.accountNumber Recipient bank account no (GBP example) Text

Send money to email recipient

If you don't know your recipient’s bank account details, you can still send money using their email address. You need to set up email recipient and then Wise will collect bank details directly from your recipient.

When you set up the transfer, we’ll email your recipient a secure link to collect their bank account details. Once your recipient provides their bank account details to us, we’re able to complete your transfer.

See below under Recipient Accounts.Create Email Recipients for more details.

Create transfer

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": <quote uuid>,
          "customerTransactionId": "<the unique identifier 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>,
    "quoteUuid": <quote uuid>,
    "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"
}

There are four steps to execute payouts:

Step 1: Create a quote

Step 2: Create a recipient account

Step 3: Create a transfer

Step 4: Fund a transfer

A transfer is a payout order you make to a recipient account based on a quote. Once created, a transfer will need to be funded within the next 14 days (7 days for email transfers) or it’ll automatically get cancelled.

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 Quote uuid. You can only create one transfer per one quote.
You cannot use same quote uuid to create multiple transfers.
Text
customerTransactionId This is required to perform idempotency check to avoid duplicate transfers in case of network failures or timeouts. Text
details.reference (optional) Recipient will see this reference text in their bank statement. Maximum allowed characters depends on the currency route. Read the Business Payments Tips article for more information. 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:

  • Always provide values for these fields
  • Always call transfers-requirements endpoint and submit values only if indicated so

Response

You need to save the 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
quoteUuid Quote uuid Text
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 Integer
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 Unique identifier assigned by customer. Used for idempotency check purposes. Text

Avoiding duplicate transfers

We use customerTransactionId field to avoid duplicate transfer requests. When your first call fails (error or timeout) then you should use the same value in customerTransactionId field that you used in the original call when you are submitting a retry message. This way we can treat subsequent retry messages as repeat messages and will not create duplicate transfers to your account.

Fund transfer

Example Request:

curl -X POST https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/transfers/{transferId}/payments \
     -H "Authorization: Bearer <your api token>" \
     -H "Content-Type: application/json" \
     -d '{ 
          "type": "BALANCE"   
         }'

Example Response:

{
  "type": "BALANCE",
  "status": "COMPLETED",
  "errorCode": null
}

There are four steps to execute payouts:

Step 1: Create a quote

Step 2: Create a recipient account

Step 3: Create a transfer

Step 4: Fund a transfer

This API call is the final step for executing payouts. Wise will now debit funds from your borderless account balance and start processing your transfer. If your borderless balance is short of funds then this call will fail with "insufficient funds" error.

Initial developer account has by default plentiful funds available for EUR, USD, GBP, and AUD.
You can add new currencies to your account via the user interface: https://sandbox.transferwise.tech

You can then top up your new currencies by converting funds from other currencies.

NB!: This endpoint is subject to additional authentication requirements. There are scenarios where those could be bypassed, such as:

  • the recipient of the transfer is marked as trusted on the website
  • the profile you are sending from is in one of the following countries:
    • United States
    • Canada
    • Australia
    • New Zealand
    • Singapore

Unless you are sending to a small number of recipients who you trust, it is recommended to implement the referenced measures for your integration.

Request

POST https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/transfers/{transferId}/payments

Use transfer id that you obtained in previous step.

Field Description Format
type "BALANCE".
This indicates that your transfer will be funded from your borderless account balance.
Text

Response

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

Field Description Format
type "BALANCE" Text
status "COMPLETED" or "REJECTED" Text
errorCode Failure reason. For example "balance.payment-option-unavailable" Text

Get 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

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. You can use webhooks to get notified about transfer status updates. Normal state flow of transfers:

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. Problematic state flow of transfers:

Outgoing Payment Sent ⇒ Bounced Back ⇒ Processing ⇒ Cancelled ⇒ Funds Refunded

Most bounce backs occur within 2-3 business days. However, to be on the safe side, we advise you to check the transfer status for potential bounce backs for 2 weeks.


Transfer state flow

alt text

NB: Transfers support rollback transitions, it allows return transfer back to one of previous states.

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

  • incoming_payment_waiting –You have submitted a transfer and it’s waiting for funding.

  • waiting_recipient_input_to_proceed – This status is only used for “send money to email” transfers. It means we’re waiting for your recipient to fill in their bank details so we can continue processing your transfer.

  • processing – We have receive your funds and are processing the transfer. Processing is a generic term and means we’re doing behind-the-scene activities before the money gets to your recipient, like AML, compliance, and fraud checks.

  • funds_converted – All compliance checks have been completed with your transfer and funds have been converted from source (your) currency to target (your recipient’s) currency.

  • outgoing_payment_sent – This means Wise has paid out funds to your recipient. This is the final state of the transfer, assuming funds will not be returned. When a transfer has this state it doesn’t mean the money has arrived in your recipient’s bank account. Note: Payment systems in different countries operate in different speeds and frequency. For example, in the UK, the payment will reach your recipient bank account within few minutes after we have sent the outgoing payment. However, in Eurozone and US, it usually takes a day until funds are available.

  • cancelled – This status is used when the transfer you created was not funded and therefore never processed. This is a final state of the transfer.

  • funds_refunded – Transfer has been refunded. This is a final state of the transfer.

  • bounced_back – Transfer has bounced back but has not been cancelled nor refunded yet. This is not a final transfer state, it means the transfer will either be delivered with delay or it will turn to funds_refunded state.

  • charged_back - This status is used when we have problem to debit payer's account or payer requested money back. Chargeback can happen from any other state.

  • unknown - This status is used when we don’t have enough information to move the transfer into a final state. We send out an email for more information. e.g. Sender account details to refund money back.

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.



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.

Check account balance

Example Request:

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

Example Response:

[
    {
        "id": 64,
        "profileId": <your profile id>,
        "recipientId": 13828530,
        "creationTime": "2018-03-14T12:31:15.678Z",
        "modificationTime": "2018-03-19T15:19:42.111Z",
        "active": true,
        "eligible": true,
        "balances": [
            {
                "balanceType": "AVAILABLE",
                "currency": "GBP",
                "amount": {
                    "value": 10999859,
                    "currency": "GBP"
                },
                "reservedAmount": {
                    "value": 0,
                    "currency": "GBP"
                },
                "bankDetails": null
            },
            {
                "balanceType": "AVAILABLE",
                "currency": "EUR",
                "amount": {
                    "value": 9945236.2,
                    "currency": "EUR"
                },
                "reservedAmount": {
                    "value": 0,
                    "currency": "EUR"
                },
                "bankDetails": null
            }
        ]
    }
]

Get available balances for all activated currencies in your account.

Request

GET https://api.sandbox.transferwise.tech/v1/borderless-accounts?profileId={profileId}

Use profile id obtained earlier to make this call.

Response

Field Description Format
id borderlessAccountId Integer
profileId Personal or business profile id Integer
recipientId Recipient id you can use for borderless top up payment order Integer
creationTime Date when balance account was opened Timestamp
modificationTime Date when balance account setup was modified Timestamp
active Is borderless account active or inactive Boolean
eligible Ignore Boolean
balances[n].balanceType AVAILABLE Text
balances[n].currency Currency code Text
balances[n].amount.value Available balance in specified currency Decimal
balances[n].amount.currency Currency code Text
balances[n].reservedAmount.value Reserved amount from your balance Decimal
balances[n].reservedAmount.currency Reserved amount currency code Text
balances[n].bankDetails Your borderless account bank details Group

Get account statement

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/borderless-accounts/{borderlessAccountId}/statement.json?
currency=EUR&intervalStart=2018-03-01T00:00:00.000Z&intervalEnd=2018-03-15T23:59:59.999Z&type=COMPACT \
     -H "Authorization: Bearer <your api token>" 

Example Response:

{
  "accountHolder": {
    "type": "PERSONAL",
    "address": {
      "addressFirstLine": "Veerenni 24",
      "city": "Tallinn",
      "postCode": "12112",
      "stateCode": "",
      "countryName": "Estonia"
    },
    "firstName": "Oliver",
    "lastName": "Wilson"
  },
  "issuer": {
    "name": "TransferWise Ltd.",
    "firstLine": "56 Shoreditch High Street",
    "city": "London",
    "postCode": "E1 6JJ",
    "stateCode": "",
    "country": "United Kingdom"
  },
  "bankDetails": null,
  "transactions": [
    {
      "type": "DEBIT",
      "date": "2018-04-30T08:47:05.832Z",
      "amount": {
        "value": -7.76,
        "currency": "EUR"
      },
      "totalFees": {
        "value": 0.04,
        "currency": "EUR"
      },
      "details": {
        "type": "CARD",
        "description": "Card transaction of 6.80 GBP issued by Tfl.gov.uk/cp TFL TRAVEL CH",
        "amount": {
          "value": 6.8,
          "currency": "GBP"
        },
        "category": "Transportation Suburban and Loca",
        "merchant": {
          "name": "Tfl.gov.uk/cp",
          "firstLine": null,
          "postCode": "SW1H 0TL  ",
          "city": "TFL TRAVEL CH",
          "state": "   ",
          "country": "GB",
          "category": "Transportation Suburban and Loca"
        }
      },
      "exchangeDetails": {
        "forAmount": {
          "value": 6.8,
          "currency": "GBP"
        },
        "rate": null
      },
      "runningBalance": {
        "value": 16.01,
        "currency": "EUR"
      },
      "referenceNumber": "CARD-249281"
    },
    {
      "type": "CREDIT",
      "date": "2018-04-17T07:47:00.227Z",
      "amount": {
        "value": 200,
        "currency": "EUR"
      },
      "totalFees": {
        "value": 0,
        "currency": "EUR"
      },
      "details": {
        "type": "DEPOSIT",
        "description": "Received money from HEIN LAURI with reference SVWZ+topup card",
        "senderName": "HEIN LAURI",
        "senderAccount": "EE76 1700 0170 0049 6704 ",
        "paymentReference": "SVWZ+topup card"
      },
      "exchangeDetails": null,
      "runningBalance": {
        "value": 207.69,
        "currency": "EUR"
      },
      "referenceNumber": "TRANSFER-34188888"
    },
    {
      "type": "CREDIT",
      "date": "2018-04-10T05:58:34.681Z",
      "amount": {
        "value": 9.94,
        "currency": "EUR"
      },
      "totalFees": {
        "value": 0,
        "currency": "EUR"
      },
      "details": {
        "type": "CONVERSION",
        "description": "Converted 8.69 GBP to 9.94 EUR",
        "sourceAmount": {
          "value": 8.69,
          "currency": "GBP"
        },
        "targetAmount": {
          "value": 9.94,
          "currency": "EUR"
        },
        "fee": {
          "value": 0.03,
          "currency": "GBP"
        },
        "rate": 1.147806
      },
      "exchangeDetails": null,
      "runningBalance": {
        "value": 9.94,
        "currency": "EUR"
      },
      "referenceNumber": "CONVERSION-1511237"
    }
  ],
  "endOfStatementBalance": {
    "value": 9.94,
    "currency": "EUR"
  },
  "query": {
    "intervalStart": "2018-03-01T00:00:00Z",
    "intervalEnd": "2018-04-30T23:59:59.999Z",
    "currency": "EUR",
    "accountId": 64
  }
}

Get borderless account statement for one currency and for specified time range. The period between intervalStart and intervalEnd cannot exceed 469 days (around 1 year 3 month).

Request

GET https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/borderless-accounts/{borderlessAccountId}/statement.json?

currency=EUR&intervalStart=2018-03-01T00:00:00.000Z&intervalEnd=2018-03-15T23:59:59.999Z&type=COMPACT

Field Description Format
borderlessAccountId Your borderlessAccountId is included in "Check account balance" response as field "id". Integer
currency Currency code Text
intervalStart Statement start time in UTC time Zulu time. Don't forget the 'Z' at the end.
intervalEnd Statement start time in UTC time Zulu time. Don't forget the 'Z' at the end.
type (optional) COMPACT (default) for a single statement line per transaction. FLAT for accounting statements where transaction fees are on a separate line. Text

Note that you can also download statements in PDF and CSV formats if you replace statement.json with statement.csv or statement.pdf respectively in the above URL.

NB! This endpoint is subject to additional authentication requirements. The additional authentication is only required once every 90 days, viewing the statement on the website or in the mobile app counts towards that as well.

Response

Field Description Format
accountHolder.type Account holder type: PERSONAL or BUSINESS Text
accountHolder.address.addressFirstLine Account holder address street Text
accountHolder.address.city Account holder address city Text
accountHolder.address.postCode Account holder address zip code Text
accountHolder.address.stateCode Account holder address state Text
accountHolder.address.countryName Account holder address country Text
accountHolder.firstName Account holder first name Text
accountHolder.lastName Account holder last name Text
issuer.name Account issuer name Text
issuer.firstLine Account issuer address street Text
issuer.city Account issuer address city Text
issuer.postCode Account issuer address zip code Text
issuer.stateCode Account issuer address state Text
issuer.country Account issuer address country Text
bankDetails Your borderless account bank details Group
transactions[n].type DEBIT or CREDIT Text
transactions[n].date Time of transaction Zulu time
transactions[n].amount.value Transaction amount Decimal
transactions[n].amount.currency Transaction currency code Text
transactions[n].totalFees.value Transaction fee amount Decimal
transactions[n].totalFees.currency Transaction fee currency code Text
transactions[n].details.type CARD, CONVERSION, DEPOSIT, TRANSFER, MONEY_ADDED, INCOMING_CROSS_BALANCE, OUTGOING_CROSS_BALANCE, DIRECT_DEBIT Text
transactions[n].details.description Human readable explanation about the transaction Text
transactions[n].details.amount.value Amount in original currency (card transactions abroad) Decimal
transactions[n].details.amount.currency Original currency code Text
transactions[n].details.sourceAmount.value Amount in source currency (conversions) Decimal
transactions[n].details.sourceAmount.currency Source currency code Text
transactions[n].details.targetAmount.value Amount in target currency (conversions) Decimal
transactions[n].details.targetAmount.currency Target currency code Text
transactions[n].details.fee.value Conversion fee amount Decimal
transactions[n].details.fee.currency Conversion fee currency code Text
transactions[n].details.rate Conversion exchange rate Decimal
transactions[n].details.senderName Deposit sender name Text
transactions[n].details.senderAccount Deposit sender bank account details Text
transactions[n].details.paymentReference Deposit payment reference text Text
transactions[n].details.category Card transaction category Text
transactions[n].details.merchant.name Card transaction merchant name Text
transactions[n].details.merchant.firstLine Merchant address street Text
transactions[n].details.merchant.postCode Merchant address zip code Text
transactions[n].details.merchant.city Merchant address city Text
transactions[n].details.merchant.state Merchant address state Text
transactions[n].details.merchant.country Merchant address country Text
transactions[n].details.merchant.category Merchant category Text
transactions[n].exchangeDetails.forAmount.value Currency exchange amount Decimal
transactions[n].exchangeDetails.forAmount.currency Currency code Text
transactions[n].exchangeDetails.rate Exchange rate Decimal
transactions[n].runningBalance.value Running balance after the transaction Decimal
transactions[n].runningBalance.currency Running balance currency code Text
transactions[n].referenceNumber Wise assigned unique transaction reference number Text
endOfStatementBalance.value Closing balance for specified time period Decimal
endOfStatementBalance.currency Closing balance currency code Text
query.intervalStart Query parameter repeated Zulu time
query.intervalEnd Query parameter repeated Zulu time
query.currency Query parameter repeated Text
query.accountId Query parameter repeated Integer

Create topup order

Step 1 - Create quote for topup:

curl -X POST https://api.sandbox.transferwise.tech/v1/quotes \
     -H "Authorization: Bearer <your api token>" \
     -H "Content-Type: application/json" \
     -d '{ 
          "profile": <your profile id>,
          "source": "EUR",
          "target": "EUR",
          "rateType": "FIXED",
          "targetAmount": 6000,
          "type": "REGULAR"
         }'

Step 2 - Find out your balance recipient account id:

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

Example Response:

[
    {
        "id": 64,
        "profileId": <your profile id>,
        "recipientId": <your balance recipient account id>,
        ...
   }
]

Step 3 - Create transfer for topup:

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 fetched in step 2>,   
          "quote": <quote id from step 1>,
          "customerTransactionId": "<the unique identifier you generated for the transfer attempt>",
          "details" : {
              "reference" : "optional text to identify your topup order"
            } 
         }'

There are 2 different ways you can send funds to your borderless account:

  1. Simply send domestic bank transfer from your bank account to your borderless account details (IBAN / SortCode-AccountNo). There is no need to setup a topup order in this case.

  2. Create a topup order and then send corresponding amount via domestic or international bank transfer to Wise escrow bank account details.

You can obtain escrow account details from your account manager.

This option is usually used when you are sending funds via international (swift) transfers.

Setting up a topup order is similar to setting up a regular transfer. Some minor changes are documented below.

1. Create topup quote

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

Same way as described in Create quote but use quote type REGULAR:

2. Find out your balance recipient account id

GET https://api.sandbox.transferwise.tech/v1/borderless-accounts?profileId={profileId}

Call Check account balance endpoint and fetch recipientId field value from the response.

This recipientId will not change, so you just need to fetch it once and then you can re-use the same value for all topup orders.

3. Create topup transfer (order)

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

As last step you now need to create a transfer (topup order). This is same call as described in Create transfer.

Use the value fetched in previous step in targetAccount field.

All done.

Going live checklist

1. Make your integration bulletproof

  • Implement basic retry mechanism to handle potential failures or network interruptions
  • Implement duplicate prevention mechanism to avoid duplicate payments. Verify that unique identifier is generated for each individual payment and that its value is kept the same in case of retrying.
  • Implement basic logging to help out in debugging and problem solving, if needed.
  • Check that you can handle all possible transfer states during polling of transfer info.
  • Automatically check available balance before submitting requests to fund your transfers. This avoids rejections due to insufficient balance.
  • Verify that your borderless account statement includes all the information you need for financial accounting.

2. Open LIVE account

  • Sign up for your Wise account and go through the onboarding flow, including the 2FA setup. Make sure your borderless account and balances are activated.

3. Set up security for LIVE environment

  • Get your live API token from Settings page.
  • Store your live API token securely in your production servers so that only authorized members of your team have access to it.

4. Do penny testing in LIVE

  • Make a small deposit into your borderless account.
  • Make few small value test payments via LIVE API before you start executing larger transfers.
  • All set. Switch it on.

5. Sign up for API status notifications.

  • You can always track our API status here.
  • Also you can sign up for API status notifications.

Third-Party Payouts Guide

This guide is an extension to Payouts Guide and it only outlines small differences between creating regular transfers and creating third party transfers. Please read through regular Payouts Guide first.

Differences

There are four steps to complete payouts:

  • Step 1: Create a quote
  • Step 2: Create a recipient account
  • Step 3: Create a transfer
  • Step 4: Fund a transfer

The difference compared to regular payouts is limited to using a different endpoint in Step 3: Create a transfer.

Instead of using our regular transfer creation API call you need to create a Third-Party Transfer instead.

This is very similar to regular Create transfers endpoint, but please note some differences:

  • Payment originator data block is additionally required.
  • originalTransferId field is being used instead of customerTransactionId

Full details how to use this endpoint can be found under API Reference section Create Third-Party Transfers.

All other functionality is available exactly same way as described under Payouts Guide above.

Limitations

  • API only. You can only create third party transfers via API. Creating third party transfers via batch file upload or via our user interface is not possible yet.
  • Email recipients are not supported. We don't support setting up third party transfers to email recipients. You can send payments to bank accounts only.
  • Some currency routes are not supported. Please contact our sales team for details.

Bank Integrations Guide

The bank integration documentation is available here: Wise for Banks API documentation

Affiliates Integration Guide

API access

Once you become our affiliate we will send you Wise Platform API access credentials: api_client_id & api_client_secret. You can then use these as username and password with Basic Authentication method.

There are two endpoints Exchange Rates.List and Get Temporary Quote which you can call with this authentication method.

TEST and LIVE environments

Get current exchange rates

Example Request (Basic authentication):

curl -X GET "https://api.sandbox.transferwise.tech/v1/rates?source=EUR&target=USD" \
     --user <your api client_id>:<your api client_secret> 

Example Response:

[
    {
        "rate": 1.166,
        "source": "EUR",
        "target": "USD",
        "time": "2018-08-31T10:43:31+0000"
    }
]

GET https://api.sandbox.transferwise.tech/v1/rates?source=EUR&target=USD

Wise updates exchange rates in nearly real-time – at least once per minute. This allows you to track and see the current mid-market exchange rate for any currency route.

See more at Exchange Rates.List

Get exchange rate history

Example Request (Basic authentication):

curl -X GET "https://api.sandbox.transferwise.tech/v1/rates?source=EUR&target=USD&from=2018-08-15T00:00:00&to=2018-08-30T23:59:59&group=day" \
     --user <your api client_id>:<your api client_secret> 

Example Response:

[
    {
        "rate": 1.166,
        "source": "EUR",
        "target": "USD",
        "time": "2018-08-15T00:00:00+0000"
    },
    {
        "rate": 1.168,
        "source": "EUR",
        "target": "USD",
        "time": "2018-06-30T00:00:00+0000"
    }
    ...
]

GET https://api.sandbox.transferwise.tech/v1/rates?source=EUR&target=USD&from=2018-08-15T00:00:00&to=2018-08-30T23:59:59&group=day

We expose up to 30 days exchange rate history via our API. This helps you to build an analysis page to show trends and implement an alerting system for your users.

See more at Exchange Rates.List

Get pricing and speed

Example Request (Basic authentication):

curl -X GET https://api.sandbox.transferwise.tech/v1/quotes?source=EUR&target=GBP&rateType=FIXED&targetAmount=600 \
     --user <your api client_id>:<your api client_secret> 

Example Response:

{
    "source": "EUR",
    "target": "GBP",
    "sourceAmount": 663.84,
    "targetAmount": 600.00,
    "type": "REGULAR",
    "rate": 0.9073,
    "createdTime": "2018-08-27T14:35:44.553Z",
    "createdByUserId": 0,
    "rateType": "FIXED",
    "deliveryEstimate": "2018-08-27T14:35:44.496Z",
    "fee": 2.34,
    "allowedProfileTypes": [
        "PERSONAL",
        "BUSINESS"
    ],
    "guaranteedTargetAmount": false,
    "ofSourceAmount": true
}

GET https://api.sandbox.transferwise.tech/v1/quotes?source=EUR&target=GBP&rateType=FIXED&targetAmount=600

Is currency route supported?

If we don't support a route then this endpoint will respond with an error code "error.route.not.supported".

How much does a transfer cost?

The Wise fee is included in the response.

How long does my transfer take?

Estimated delivery time is included in the response. This can vary quite a lot for different currency routes. For example transfers often only take a few hours from EUR to GBP, while sending money from USD can take 1-2 business days. This endpoint allows you to find out the estimated delivery time for each currency route.

See more at Get Temporary Quote









Connected Apps Integration Guide

With Connected Applications, you can let your customers connect their Wise accounts to your product. Say you’re an accounting software – doing this could let your customers automate reconciliation. If you’re a payroll company, you could push customer payments right into Wise. You could even push Wise notifications through your app. Whatever you want to build, you likely could!

We need to take a deeper look into your application use case and the added value it will bring to our joint customers in order to authorise such an integration. So before starting the technical work please contact our sales team for more info on how to get started.

This guide describes how your application can connect to Wise customer accounts. It also describes some common operations that are useful for application integrations.

API access

Wise uses the OAuth 2.0 protocol for authorization. Once our partnership begins, we'll send you API access credentials for our sandbox environment. These credentials consist of a client ID and a client secret. The client ID and secret are required for an OAuth 2.0 authorization code-based account linking flow. Later, you will receive a different set of client credentials for our live environment.

Your technical team will need to provide Wise with a redirect URL for the account linking flow. This is the URL controlled by your system that we will forward users to after successfully granting your application access to Wise accounts. Specifying this URL explicitly makes the integration more secure. We will only use redirect URLs registered with us when redirecting our users to your system.

This article about the OAuth 2.0 framework is a great way to refresh your knowledge about the protocol itself.

Sandbox and live environments

User authorization

At a high level, there are five steps to gaining access to an existing Wise account:

  1. Your application redirects the user to the Wise authorization page, which prompts them to log in.
  2. The user logs in to Wise.
  3. The user agrees to give your application access to one of their Wise profiles.
  4. Wise redirects the user back to your preconfigured redirect URL, with an authorization code and selected profile ID appended as URL query parameters.
  5. Your application exchanges the authorization code for API tokens.

These steps are explained in more detail below.

1. Your application redirects the user to Wise authorization 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}&state={state}

Live:

https://wise.com/oauth/authorize/?client_id={clientId}&redirect_uri={redirectUri}&state={state}

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 URL. More about state parameter.

2. The user logs in to Wise

Our usual login screens are presented to the user if they are not already logged in on the browser being used. Users will be prompted to go through our two-factor authentication procedure if that is enabled for their account.

3. The user creates or selects a profile

The Wise user will create or select a profile that will be linked with your application. Wise profiles are the personal or business entities which will be involved in money transfers and other Wise activities.

Once the authorization process is complete, your app will be authorized to perform actions on the selected profile. Access to other profiles associated with the Wise user must be separately authorized.

4. The user agrees to grant access and we forward them to your system

Once a user gives your application authorization to connect to Wise and access their data, they will be redirected back to your redirect URL with some additional query parameters.

Parameter Description
code Authorization code used to complete the authorization code grant-based OAuth 2.0 flow
state Any state parameter you initially passed to us when initiating the flow
profileId The profile ID that the Wise user granted you access to

An example, given the redirect URL https://www.yourapp.com:

https://www.yourapp.com/?code=ABCDEF&state=f6027a42-344d-4a4d-9f8a-39e42acf9887&profileId=12345

If you are building your Wise 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.

5. Your application exchanges the authorization code for API tokens

Your website or service can then use the authorization code to obtain API tokens to act on behalf of the user account as described in the get user tokens section.

Please note that authorization codes expire after 30 minutes and are one time use only.

Error handling

When errors occur during authorization request handling, we display error details on our web pages. The user may also see a link back to your application, with error and error_description parameters in the URL instead of code. Your callback URL handler should be prepared to accept such "error" requests.

Get user tokens

Authorization codes can be used to obtain user access and refresh tokens. These allow your system to make API calls on behalf of a Wise user.

Access tokens are short-lived API tokens used to access Wise customer API resources.

Refresh tokens are long-lived API tokens that are used to generate access tokens.

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.yourapp.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"
  }

You need to include the user's access token in API requests using an Authorization HTTP request header:

`Authorization: Bearer <access token>`

Access tokens are short-lived for security reasons. They are only valid for 12 hours. When they expire, you need to use the refresh token to generate a new access token.

You must securely store the user's refresh token in order to generate new access tokens. Refresh tokens (or your client credentials) should never be transmitted to any of your client applications.

Request

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

Use Basic Authentication with your api-client-id/api-client-secret as the username/password. The body of the request must be sent as x-www-form-urlencoded.

Field Description Format
grant_type "authorization_code" Text
client_id Your API client ID Text
code Authorization code provided to you upon redirect back from the authorization flow. See User authorization. Text
redirect_uri Redirect URL 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. Text
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. Text
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 the refresh token to generate a 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.

Depending on how your application uses the Wise Platform API, you may find that requesting a new access token before attempting a series of API calls on behalf of an individual user will avoid issues with expired access tokens.

Request

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

Use Basic Authentication with your api-client-id/api-client-secret as the username/password. The body of the request must be sent as x-www-form-urlencoded.

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

Response

Field Description Format
access_token Access token to be used when calling API endpoints on behalf of user. Valid for 12 hours. Text
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 Text
expires_in Expiry time in seconds Integer
scope "transfers" Text

Refresh token expiry

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

  • The user revokes access for your application to their account.
  • The user enables enhanced security on their Wise account.
  • Wise revokes the token due to a security breach of your client secret.

Your application should handle a failing refresh token scenario by sending the user through the authorization code flow as you initially did.

Getting started with Wise profiles

Once a Wise user has connected their profile to your application, your system can start interacting with that profile's Wise Platform API resources. The Wise Platform API can be used to generate quotes for money transfers, set up recipients for payments, set up money transfers, and so on as described in our full API documentation.

Once you acquire an API access token for a profile you can immediately start using the API on the customer's behalf. However, there are some considerations that are important to avoid problems when working with Wise profiles.

Verification status

Wise is obliged to verify the identity of personal and business profiles as part of our Know Your Customer policy. We must be satisfied that we know our customers well enough before conducting financial transactions with them.

Verification involves the Wise customer submitting various forms of evidence to us for our consideration. Evidence can include official documents, for example. We may accept or reject such evidence, or consider some evidence as being superior to other forms of evidence.

What evidence we have verified for a profile can affect how successful or how quickly money transfers can be made. For certain values of transfer, or certain currency routes, we may require a certain level of verification. If we do not consider that a profile has been sufficient verified for a particular money transfer, we might delay the processing of the transfer while we seek further information from the customer.

For more information on verification: How does Wise verify my identity?

If you intend to use the Wise Platform API to set up money transfers, then it is desirable for you to know whether such verification issues might delay or prevent transfers from succeeding. This is particularly relevant for profiles that have just been created as part of linking your application to Wise: new profiles may not yet be verified, and money transfers may be delayed while this process happens, leading to a bad experience for our customers.

Wise exposes the verification status of a profile to help connected applications understand when money transfers are able to be created without such verification issues (but see below for an important caveat).

Verification status is a simple indicator of the current level of verification that has been made for a profile to some particular level of confidence: a level that is likely to allow money transfers to occur without being delayed by verification-related issues.

Verification status is exposed as a property of a profile: i.e. a profile is verified or not verified. It is useful to have such a property as a "gate" in the connected application's system that prevents transfers from being created before they are likely to be processed without delays.

Connected applications can query the verification status of a profile using the Wise Platform API. Wise can also asynchronously notify connected applications about the change in a profile's verification status using a webhook notification.

Verification status integration strategy

The following strategy may be useful for your integration with respect to profile verification:

  1. At some point before going live to your customers, you set up an "application" webhook subscription for verification status change events. This is a single subscription that will allow you to receive verification status events related to any profile that links to your application in the future. (See here for more information.)
  2. After going live, a user connects their profile to your application using the OAuth authorization flow. (Note that the profile might be an existing, verified profile, or a brand new, unverified profile).
  3. During the authorization flow, your system receives an authorization code and Wise profile ID in a request to your callback endpoint (see User authorization). Once API tokens have been acquired using the authorization code, you now have API tokens and the related profile ID: you can now access the profile's API resources.
  4. The verification status of the profile is queried using the Wise Platform API. If the response indicates the profile is "verified", you can proceed with transfer operations. If the response indicates "not verified", then transfers are likely to be delayed: you should wait to receive a webhook notification for the customer.
  5. If a profile is unverified, the verification process takes place. Later, when verification completes successfully, you will receive a webhook notification informing you that the profile has become verified: you may then allow transfer creation. (Alternatively, you can continue to poll the API again, but this is not recommended.)

Checking verification status using the API

You can check the verification status of a profile using the following API. This is a profile-specific API resource which should be accessed using an access token acquired for the profile.

Example Request:

    curl -X GET 'https://api.sandbox.transferwise.tech/v3/profiles/12345/verification-status' \
        -H "Authorization: Bearer <profile's access token>"

Request

GET https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/verification-status

Field Description Format
profileId Profile ID Integer

Example Response:

{
  "profileId": 12345,
  "currentStatus": "verified"
}

Response

Field Description Format
profileId Profile ID Integer
currentStatus Current verification status Verification status code (see below)
Verification status code Description
verified The profile is sufficiently verified to start making payments (note that some regional limits may still apply)
not_verified The profile is currently awaiting verification or there are pending issues with the verification process

Please note that we do not expose any finer details of customer verification.

Verification State Change webhook

You can subscribe to profiles#verification-state-change event to be notified when the user is ready to use Wise.

Open Banking

Base Open Banking URL in Sandbox

https://openbanking.sandbox.transferwise.tech

Base Open Banking URL in Production

https://openbanking.transferwise.com

The Wise Open Banking API is aimed for Financially Regulated Third Party Providers who can prove their regulatory status either by being a member of the Open Banking Directory or possessing an eIDAS Certificate. Third Parties or individuals who do not meet these requirements are welcome to check out our Public API.

The Wise Open Banking API is a collection of RESTful APIs that enable Third Party Providers (TPPs) to access account information, initiate payments and confirm availability of funds on behalf of Wise customers. The API implementation follows the Open Banking UK standard, and Wise is a registered member of the Open Banking Directory.

Through this API you can either query account information, if you're an Account Information Service Provider (AISP), initiate payments, if you're a Payment Initiation Service Provider (PISP), or confirm the availability of funds, if you're a Card Based Payment Instrument Issuer (CBPII). We are currently supporting version 3.1.1 of the Open Banking API.

Contingency Mechanism

We offer our bespoke Connected Applications API as a secondary API, acting as a contingency mechanism. The Connected Applications API provide the same set of functionality for both AISPs and PISPs as our Open Banking API does. In order to avoid any delays in switching over to the contingency mechanism during a major outage of the Open Banking API, we encourage TPPs to preemptively seek out registration to our contingency mechanism by reaching out to openbanking@wise.com and specifically requesting access to the contingency mechanism.

Prerequisites

Well-Known Open Banking URL in Sandbox

https://sandbox.transferwise.tech/openbanking/.well-known/openid-configuration

Well-Known Open Banking URL in Production

https://wise.com/openbanking/.well-known/openid-configuration

There's a couple of things you should be aware of in order to connect to the Wise Open Banking API:

  • Being a registered TPP under the Open Banking Directory will ease the integration process.
  • We are using mutualTLS as the means for authentication. Moreover, the CN of your client certificate is expected to match the clientId under which you are registered.
  • You need to register your client, before you'll be able to call any of the APIs. Check out the Sandbox Access first.

For a detailed description of requirements and supported algorithms please check out the Well-Known Open Banking URL.

Dynamic Client Registration

Dynamic Client Registration URL in Sandbox

https://openbanking.sandbox.transferwise.tech/open-banking/v3.3/register

Dynamic Client Registration URL in Production

https://openbanking.transferwise.com/open-banking/v3.3/register

If you're a registered TPP at the Open Banking Directory you can simply use our Dynamic Client Registration endpoint to self-onboard your organization using the Software Statement Assertion issued by the Open Banking Directory.

Confirmation of Payee clients

In case you're looking to onboard a Confirmation of Payee (CoP) client please make sure to include the cop scope into the list of requests scopes. The list of requested scopes should be

"scope": "openid openbanking payments cop"

Sandbox Access

We highly recommend that you get started with connecting to our sandbox first, before moving on to production. To get started with the registration process drop us an email to openbanking@wise.com.

Open Banking Directory

If you're a registered TPP in the Open Banking Directory you will probably be using a Signing and a Transport certificates issued by Open Banking. At the moment we accept the old style OB Transport and OB Signing certificates.

You can easily onboard by providing a Software Statement Assertion (SSA) generated in the Open Banking Directory.

Please make sure to have your list of Redirect Uri-s correctly configured in your Software Statement, otherwise you'll not be able to go through the whole flow.

eIDAS Certificates

In case you're using an eIDAS certificates instead of the ones issued by the Open Banking Directory just contact us at openbanking@wise.com to see how we can move forward.

Sandbox Test User

You can sign up for a test user account here https://sandbox.transferwise.tech/register. The 2FA code used for any subsequent logins to the sandbox will alway be 111111.

You'll be asked to set up a developer account by filling in your profile information. Once this is done, you'll see that your newly created profile comes with a couple of test accounts opened and some test funds in them.

You do NOT need to create an API Token via the web interface in case you're intention is to use this test user for the Open Banking flow.

Sandbox Test Flow

After you've successfully applied for the Sandbox Access and you've set up a Sandbox Test User you are ready to test the Open Banking flow. For the purpose of this test flow let's assume that your TPP is an AISP and it's registered with the following details

Client ID Redirect URI Authorized Scopes
ob-dummy-tpp https://ob-dummy-tpp/redirect accounts

1. Create an Access Token

Example Token Request

curl -X POST \
  https://openbanking.sandbox.transferwise.tech/open-banking/auth/token \
  --cacert CA.pem --cert client.pem --key client.key \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=client_credentials&scope=accounts'

Example Response

{
    "access_token": "abcd1234-abcd-1234-abcd-abcdef123456",
    "token_type": "bearer",
    "expires_in": 6000,
    "scope": "accounts openbanking"
}

As a first step you'll need to request an access token from the Token Endpoint.

Request

POST https://openbanking.sandbox.transferwise.tech/open-banking/auth/token

Field Description Format
grant_type OAuth Grant Type client_credentials
scope The requested scopes Space separated list

You must include the requested scope in your token request. As an AISP your requested scope will be accounts.

Response

Field Description Format
access_token The access token Text
expires_in Expiration time in seconds Long
scope The scopes you have been given access to Text

2. Create a Consent

Example Create Consent Request

curl -X POST \
  https://openbanking.sandbox.transferwise.tech/open-banking/v3.1/aisp/account-access-consents \
  --cacert CA.pem --cert client.pem --key client.key \
  -H 'Authorization: Bearer abcd1234-abcd-1234-abcd-abcdef123456' \
  -H 'Content-Type: application/json' \
  -d '{
  "Data": {
    "Permissions": [
      "ReadAccountsBasic", "ReadTransactionsBasic", "ReadTransactionsDebits"
    ]}}'

Example Response

{
    "Data": {
        "Status": "AwaitingAuthorisation",
        "ConsentId": "123"
    }
}

Request

POST https://openbanking.sandbox.transferwise.tech/open-banking/v3.1/aisp/account-access-consents

Using the access-token returned from Creating an Access Token you can create a new consent object. Use the authorization header:

Authorization: Bearer xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx

The payload of this request will look different depending on whether you're an AISP, PISP or CBPII. For an AISP you'll need to specify a set of permissions describing the access that you wish to gain on behalf of the end user.

Permissions

For AISPs the list of supported permissions is:

  • ReadAccountsBasic
  • ReadAccountsDetail
  • ReadBalances
  • ReadTransactionsBasic
  • ReadTransactionsCredits
  • ReadTransactionsDebits
  • ReadTransactionsDetail
  • ReadDirectDebits

Response

The response will be JSON data reflecting the newly created consent object. There are two important return values to highlight here.

  • Data.Status will contain AwaitingAuthorisation because this consent has not been authorized by the user yet.
  • Data.ConsentId will contain the unique identifier assigned to your consent object. Save this, as you'll need it later.

3. User Flow

Example Authorization Request

https://sandbox.transferwise.tech/openbanking/authorize?
  response_type=code%20id_token&
  redirect_uri=https://ob-dummy-tpp/redirect&
  scope=openid%20accounts&
  client_id=ob-dummy-tpp&
  state=state123&
  nonce=nonce123&
  request=eyJ0...sYjmjJg

Example Authorization JWT Request

HEADER

{
   "kid" : "er84c2cYa6dAe57BV3278Pf",
   "alg" : "PS256",
   "typ" : "JWT"
}

PAYLOAD

{
   "scope" : "openid accounts",
   "response_type" : "code id_token",
   "sub" : "user_id",
   "claims" : {
      "id_token" : {
         "openbanking_intent_id" : {
            "essential" : true,
            "value" : "123"
         },
         "acr" : {
            "values" : [
               "urn:openbanking:psd2:sca",
               "urn:openbanking:psd2:ca"
            ],
            "essential" : true
         }
      },
      "userinfo" : {
         "openbanking_intent_id" : {
            "value" : "123",
            "essential" : true
         }
      }
   },
   "iss" : "ob-dummy-tpp",
   "client_id" : "ob-dummy-tpp",
   "aud" : "https://openbanking.sandbox.transferwise.tech",
   "exp" : 2499287201,
   "iat" : 2499283601,
   "max_age" : 86400,
   "redirect_uri" : "https://ob-dummy-tpp/redirect"
}

At the moment we are only supporting the browser redirect flow (Hybrid Flow) for authorizing the created consent.

The customer journey will start from the TPPs website from where a user action will trigger a redirect to the Wise Open Banking Authorization Endpoint

GET https://sandbox.transferwise.tech/openbanking/authorize

Parameter Required Description
response_type Mandatory code id_token
redirect_uri Mandatory One of the pre-registered redirect URIs
scope Mandatory Must include openid plus any requested scope
client_id Mandatory Pre-registered clientId of the TPP
request Mandatory JWT Request Object
state Optional If present, it must also be present in the JWT
nonce Optional If present, it must also be present in the JWT

You can take a look at the example JWT request object on the right. Please note that:

  • Every request parameter sent in the URL must also be present in the signed JWT.
  • The aud claim should be correctly filled as https://openbanking.sandbox.transferwise.tech
  • The openbanking_intent_id must be filled with a valid ConsentId issued to the TPP.
  • The JWT must be signed with a valid signing certificate.

Once the TPP redirects the user browser to the Authorization Endpoint the following things will happen in order:

  1. User Login (use the username and password from the Test User Registration)
  2. Pass 2FA challenge (User the code 111111 in sandbox)
  3. Select profile you wish to give access to (Business or Personal)
  4. Review and Authorize Consent
  5. Redirect back to TPP

As part of the last step, the user browser is redirected to the TPP with the following parameters

Parameter Required Description
code Mandatory The authorization_code issued as the request of the request
id_token Mandatory Signed JWT containing details about the authorization
state Optional In case it was provided with the request

Note that in case the authorization request fails either because of a validation error on the request, or because the enduser drops off, we still redirect the user browser to the TPP with an error response of the following format:

Field Description Format
error Error code according to RFC6749 Text
error_description Detailed explanation of error Text

4. Exchange Authorization Code for Access Token

Example Token Request

curl -X POST \
  https://openbanking.sandbox.transferwise.tech/open-banking/auth/token \
  --cacert CA.pem --cert client.pem --key client.key \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=authorization_code&redirect_uri=https%3A%2F%2Fob-dummy-tpp%2Fredirect&code=abcdauthcode'

Example Response

{
    "access_token": "zzzzzzzz-1111-2222-3333-zzzzzzzzzzzz",
    "token_type": "bearer",
    "refresh_token": "refreshr-efre-shre-fres-hrefreshrefr",
    "expires_in": 6000,
    "scope": "accounts consent-id:123 openbanking openid"
}

Once you get the authorization code after the browser redirect, you'll have to call the Token Endpoint to exchange this for a valid access token.

Request

POST https://openbanking.sandbox.transferwise.tech/open-banking/auth/token

Field Description Format
grant_type OAuth Grant Type authorization_code
redirect_uri Pre-registered redirect Uri URI
code Authorization Code Text

Response

Field Description Format
access_token The access token Text
expires_in Expiration time in seconds Long
scope The scopes you have been given access to Text
refresh_token Refresh Token for refreshing access token Text

5. Query the API

Example Request

curl -X GET \
  https://openbanking.sandbox.transferwise.tech/open-banking/v3.1/aisp/accounts \
  --cacert CA.pem --cert client.pem --key client.key \
  -H 'Authorization: Bearer zzzzzzzz-1111-2222-3333-zzzzzzzzzzzz' \

Example Response

{
    "Data": {
        "Account": [
            {
                "AccountId": "504",
                "Currency": "GBP",
                "AccountType": "Personal",
                "AccountSubType": "EMoney",
                "Account": [
                    {
                        "SchemeName": "UK.OBIE.SortCodeAccountNumber",
                        "Identification": "230xxx1000xxxx",
                        "Name": "John Smith (GBP)"
                    }
                ],
                "Servicer": {
                    "SchemeName": "UK.OBIE.BICFI",
                    "Identification": "TRWIGB22"
                }
            }
        ]
    }
}

With the access-token from Authorization Code Flow used in the Authorization header, you'll be able to query the data endpoints.

Authorization: Bearer xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx







AISP Interfaces

Accounts

Querying the accounts endpoint will return all open currency accounts of the consented user.

GET /open-banking/v3.1/aisp/accounts

GET /open-banking/v3.1/aisp/accounts/{id}

Note: Not every Borderless Account opened in Wise has a unique set of bank details attached to it. Therefore, it's expected that some of the currency accounts returned will have an empty OBReadAccount3/Data/Account/Account. We encourage AISPs to instead use the unique id OBReadAccount3/Data/Account/AccountId for identifying different accounts. There's nothing inherently different between accounts with and without bank details, you can call the Balances and Transactions endpoints for either of them.

Balances

Querying the balances endpoint will return the current running balance of a specific account.

GET /open-banking/v3.1/aisp/accounts/{id}/balances

Transactions

Querying the transactions endpoint will return a list of transactions from within the consented time window.

GET /open-banking/v3.1/aisp/accounts/{id}/transactions

We are fully transparent about our transaction charges, so you will find fees attached to transactions in either of the following ways:

  • Embedded [DEFAULT]: Using the OBReadTransaction5/Data/Transaction/ChargeAmount object. Fees represented this way will be embedded into the transactions amount. This might make sense for most AISPs.
  • Fee Split : Showing fees as separate DEBIT transactions with an attached reference to the original transaction. Fees represented this way will not be embedded in the original transaction amount. This might make sense for some AISPs, like account software providers.

Direct Debits

Querying the direct debits endpoint will return the list of set up direct debits on a specific account

GET /open-banking/v3.1/aisp/accounts/{id}/direct-debits

PISP Interfaces

Every consent object created for initiating payments will have a CutOffDateTime attached which is set to be 30 minutes after the creation of the consent. After the 30 minutes have lapsed, the Payment Order creation will be rejected.

We are supporting both UK.OBIE.SortCodeAccountNumber as well as UK.OBIE.IBAN for account identification.

At the moment we are only able to pass on a single reference to the debtor, which is Initiation/RemittanceInformation/Reference if present, or Initiation/EndToEndIdentification otherwise. The accepted size of the reference field varies based on the currency of the transfer. For EUR transfers you'll be able to leverage the full length of 35 characters of this field, however for GBP transfers this field length is restricted to a maximum of 18 characters. The reason for this restriction is also detailed in OB Payment Message Format Mapping. In case of FPS, this field gets mapped to both ISO8583 Field 62 as well as Field 120.

Domestic Payments

POST /open-banking/v3.1/pisp/domestic-payments

GET /open-banking/v3.1/pisp/domestic-payments/{id}

The Domestic Payments endpoint can be used to initiate same currency transfers. You can initiate domestic payments in any of the supported currencies by Wise, assuming the consenting user already holds an open account in the requested currency.

International Payments

POST /open-banking/v3.1/pisp/international-payments

GET /open-banking/v3.1/pisp/international-payments/{id}

The International Payments endpoint can be used to initiate transfers where the source currency is different than the target currency. You can use it to initiate a payment with:

  • Fixed Source Amount : OBInternational2/InstructedAmount/Currency and OBInternational2/CurrencyOfTransfer are different.

    • The source currency and amount are specified using OBInternational2/InstructedAmount. The currency can be any of the supported currencies by Wise, assuming the consenting user already holds an open account in the requested currency.
    • The target currency of the transfer is specified using OBInternational2/CurrencyOfTransfer. The instructed amount will be converted to the CurrencyOfTransfer and sent out to the specified CreditorAccount.

  • Fixed Target Amount : OBInternational2/InstructedAmount/Currency and OBInternational2/CurrencyOfTransfer are the same.

    • The source currency of the transfer can either be specified using OBInternational2/ExchangeRateInformation/UnitCurrency, or it can be left unspecified, allowing the Wise customer to choose one of his eligible currency accounts during the Authorization Flow. The customer's choice of source currency, the exchange rate used, and any additional charges are clearly communicated to the customer as well as reflected to the TPP via the Payment Resource.
    • The target currency and amount are specified using OBInternational2/InstructedAmount.

We are only supporting INDICATIVE ExchangeRateInformation during the creation of the International Payment Consent. The real exchange rate used, along with any fees will be clearly communicated to the customer during the consent authorization, as well as reflected to the PISP during the creation of the International Payment Resource.

CBPII Interfaces

POST /open-banking/v3.1/cbpii/funds-confirmations

The confirmation of funds endpoint can be used to check whether the consented user has a specific amount on any of its opened currency accounts.

Global Currencies

Global Currencies is a Wise product that allows customers to send currencies to countries other than the one they are domestic to. For example, sending US dollars to a person or business 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 Wise Platform 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": "swift_code") 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.

Global currency warning message

In addition, if you offer this product, you must be sure to display a message to customers that there are potentially additional extra fees for this type of transfer. For example:

To send this transfer, we need to use the SWIFT network, which is more expensive and slower than normal transfers. There may also be extra fess taken from the money by intermediary banks. We cannot guarantee the exact amount that will be received by your recipient.

There are three cases you need to cover where we will use the SWIFT network and the message needs to be displayed:

  1. A USD recipient of type swift_code
  2. A GBP recipient of type iban where the IBAN does not start with GB
  3. A EUR recipient of type iban where the IBAN does not start with one of the following codes (i.e. the transfer is to a non-SEPA country):
    • AT
    • BE
    • CY
    • DE
    • EE
    • ES
    • FI
    • FR
    • GR
    • IE
    • IT
    • LT
    • LU
    • LV
    • MC
    • MT
    • NL
    • PT
    • SI
    • SK
    • SM

Example: Creating a global currency USD 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 swift_code 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 field 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. The payOut field informs you which paymentOption to select, in this case you should show the user the fees to pay using the option that has a pay out of SWIFT. You should use the payIn option that has previously been agreed up, by default this is BANK_TRANSFER unless you are using a prefunded or bulk settlement model.

Versioning

The Wise Platform API is continuously evolving as we offer new features and coverage to our API customers. Here we explain how our API versioning is maintained so you know what to expect.

It's important to us that third-party integrations are not adversely affected by changes and we endeaver to uphold these standards as part of making convenience and transparency part of our company's mission. We are regularly reviewing our policies to make sure we're delivering the best possible API developer experience.

These policies apply to both our REST API and our webhooks (push-based event API).

Breaking changes

A breaking change refers to any change that would require a client to update their application in order to continue working with the API as originally intended. If an API field or resource is removed or renamed, then a breaking change has taken place. In this case we will increment the version of the affected API endpoints to prevent breaking existing customer integrations.

Under our current policy API endpoints are not all versioned together, if API endpoint compatibility has changed in the new version as a result of a breaking change we will provide clear instructions in our documentation on which API calls must be used together.

Continuity (non-breaking) changes

Wise reserves the right to make additive changes to our API without incrementing the version number or notifying clients. We may add new resources, fields, and relationships to an existing version of the API and these will not be considered breaking changes.

For example, if we add a new relationship to the Transfer resource for a “parent_order”, we will neither bump the API version nor notify our customers before releasing the update. We will, however, update our API documentation explaining the purpose of the changes.

As such, clients should design their applications to be flexible enough to not break when new fields are added to resources.

Removal of existing API endpoints

It is not standard policy for Wise to remove or disable API versions, and we will not take this action lightly. However in some cases it may be necessary; for example if the affected API does not meet new regulatory requirements and there is no alternative to making a breaking change and disabling an old API.

In the extremely rare case that this is necessary we will not remove API endpoints without notice to clients who may be affected, and formal warning of at least 6 months as long as this complies with our regulatory obligations.

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 sign up here.

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

Making lots of payments?
We have a dedicated team to talk to you. https://wise.com/business/contact

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

Want more information about your payments?
Lookup Wise Support Centre details. https://wise.com/contact

Addresses

Create/Update

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",
            "occupations": [
              {
                "code": "Software Engineer",
                "format": "FREE_FORM"
              }
            ]
          }
        }'

Example Response:

{
  "id": 236532,
  "profile": <your profile id>,
  "details": {
    "country": "EE",
    "firstLine": "Narva mnt 5-1",
    "postCode": "10113",
    "city": "Tallinn",
    "state": "",
    "occupation": null,
    "occupations": [
      {
        "code": "Software Engnieer",
        "format": "FREE_FORM"
      }
    ]
  }
}

Adds address info to user profile. List of required fields are different for different countries.

State field is required for US, CA, BR and AU addresses.

Occupations is required for CA, IN, JP and within the US for the states AZ and NM. If you serve any of these jurisdictions we recommend submitting occupation for all customers for simplicity, however if this is an issue we can discuss alternative solutions.

Request

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

Field Description Format Validation Rules
profile User profile id. Integer ID of the user's personal or business profile
details.country 2 digit ISO country code. Text Two digit ISO code
details.firstLine Address line: street, house, apartment. Text
  • Must not be a PO box
  • Must not be made up of only special characters from regex `[!@#\$%^&*(),.?":{}
details.postCode Zip code Text (max 30 chars) Some country selections will check for valid post codes, e.g. Canada
details.city City name Text Is not "PO Box"
details.state State code. Required if country is US, CA, AU, BR Text Is valid state code for selected country (only required for US, BR, AU and CA)
details.occupation (Deprecated) User occupation. Required as described above. Text This is deprecated - the the occupations field below
details.occupations Array of occupations, currently one FREE_FORM occupation is supported, required as described above. Array (can be null or empty) Array
details.occupations[n].code User occupation Text Any value permitted
details.occupations[n].format Occupation type Text Always FREE_FORM

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 (Deprecated) User occupation. Required for US, CA, JP Text
details.occupations details.occupations Array of occupations, currently one FREE_FORM occupation is supported, required as described above.
details.occupations[n].code User occupation, any value permitted. Text
details.occupations[n].format Occupation type - always FREE_FORM 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,
    "occupations": 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,
            "occupations": 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)
  1. 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.

  2. 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.

  3. 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.

  4. 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

Borderless Accounts

Get Account Balance

Example Request:

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

Example Response:

[
    {
        "id": 64,
        "profileId": <your profile id>,
        "recipientId": 13828530,
        "creationTime": "2018-03-14T12:31:15.678Z",
        "modificationTime": "2018-03-19T15:19:42.111Z",
        "active": true,
        "eligible": true,
        "balances": [
            {
                "balanceType": "AVAILABLE",
                "currency": "GBP",
                "amount": {
                    "value": 10999859,
                    "currency": "GBP"
                },
                "reservedAmount": {
                    "value": 0,
                    "currency": "GBP"
                },
                "bankDetails": null
            },
            {
                "balanceType": "AVAILABLE",
                "currency": "EUR",
                "amount": {
                    "value": 9945236.2,
                    "currency": "EUR"
                },
                "reservedAmount": {
                    "value": 0,
                    "currency": "EUR"
                },
                "bankDetails": {
                    "id": 90,
                    "currency": "EUR",
                    "bankCode": "DEKTDE7GXXX",
                    "accountNumber": "DE51 7001 1110 6050 1008 91",
                    "swift": "DEKTDE7GXXX",
                    "iban": "DE51 7001 1110 6050 0008 91",
                    "bankName": "Handelsbank",
                    "accountHolderName": "Oliver Wilson",
                    "bankAddress": {
                        "addressFirstLine": "Elsenheimer Str. 41",
                        "postCode": "80687",
                        "city": "München",
                        "country": "Germany",
                        "stateCode": null
                    }
                }
            }
        ]
    }
]

Get available balances for all activated currencies in your borderless account.

Request

GET https://api.sandbox.transferwise.tech/v1/borderless-accounts?profileId={profileId}

Use profile id obtained earlier to make this call.

Response

Field Description Format
id Borderless account id Integer
profileId Personal or business profile id Integer
recipientId Recipient id you can use for borderless topup transfer Integer
creationTime Date when balance account was opened Timestamp
modificationTime Date when balance account setup was modified. Timestamp
active Is borderless account active or inactive Boolean
eligible Ignore Boolean
balances[n].balanceType AVAILABLE Text
balances[n].currency Currency code Text
balances[n].amount.value Available balance in specified currency Decimal
balances[n].amount.currency Currency code Text
balances[n].reservedAmount.value Reserved amount from your balance Decimal
balances[n].reservedAmount.currency Reserved amount currency code Text
balances[n].bankDetails Bank account details assigned to your borderless account. Available for EUR, GBP, USD, AUD, NZD Group
balances[n].bankDetails.id Bank account details id Integer
balances[n].bankDetails.currency Bank account currency Text
balances[n].bankDetails.bankCode Bank account code Text
balances[n].bankDetails.accountNumber Bank account number Text
balances[n].bankDetails.swift Bank account swift code Text
balances[n].bankDetails.iban Bank account iban Text
balances[n].bankDetails.bankName Bank name
balances[n].bankDetails.accountHolderName Bank account holder name Text
balances[n].bankDetails.bankAddress.addressFirstLine Bank address street and house Text
balances[n].bankDetails.bankAddress.postCode Bank address zip code Text
balances[n].bankDetails.bankAddress.city Bank address city Text
balances[n].bankDetails.bankAddress.country Bank address country Text
balances[n].bankDetails.bankAddress.stateCode Bank address state code Text

Get Account Statement

This endpoint is SCA protected when it applies, you can find more info here.

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/borderless-accounts/{borderlessAccountId}/statement.json?
currency=EUR&intervalStart=2018-03-01T00:00:00.000Z&intervalEnd=2018-03-15T23:59:59.999Z&type=COMPACT \
     -H "Authorization: Bearer <your api token>" 

Example Response:

{
  "accountHolder": {
    "type": "PERSONAL",
    "address": {
      "addressFirstLine": "Veerenni 24",
      "city": "Tallinn",
      "postCode": "12112",
      "stateCode": "",
      "countryName": "Estonia"
    },
    "firstName": "Oliver",
    "lastName": "Wilson"
  },
  "issuer": {
    "name": "TransferWise Ltd.",
    "firstLine": "56 Shoreditch High Street",
    "city": "London",
    "postCode": "E1 6JJ",
    "stateCode": "",
    "country": "United Kingdom"
  },
  "bankDetails": null,
  "transactions": [
    {
      "type": "DEBIT",
      "date": "2018-04-30T08:47:05.832Z",
      "amount": {
        "value": -7.76,
        "currency": "EUR"
      },
      "totalFees": {
        "value": 0.04,
        "currency": "EUR"
      },
      "details": {
        "type": "CARD",
        "description": "Card transaction of 6.80 GBP issued by Tfl.gov.uk/cp TFL TRAVEL CH",
        "amount": {
          "value": 6.8,
          "currency": "GBP"
        },
        "category": "Transportation Suburban and Loca",
        "merchant": {
          "name": "Tfl.gov.uk/cp",
          "firstLine": null,
          "postCode": "SW1H 0TL  ",
          "city": "TFL TRAVEL CH",
          "state": "   ",
          "country": "GB",
          "category": "Transportation Suburban and Loca"
        }
      },
      "exchangeDetails": {
        "forAmount": {
          "value": 6.8,
          "currency": "GBP"
        },
        "rate": null
      },
      "runningBalance": {
        "value": 16.01,
        "currency": "EUR"
      },
      "referenceNumber": "CARD-249281"
    },
    {
      "type": "CREDIT",
      "date": "2018-04-17T07:47:00.227Z",
      "amount": {
        "value": 200,
        "currency": "EUR"
      },
      "totalFees": {
        "value": 0,
        "currency": "EUR"
      },
      "details": {
        "type": "DEPOSIT",
        "description": "Received money from HEIN LAURI with reference SVWZ+topup card",
        "senderName": "HEIN LAURI",
        "senderAccount": "EE76 1700 0170 0049 6704 ",
        "paymentReference": "SVWZ+topup card"
      },
      "exchangeDetails": null,
      "runningBalance": {
        "value": 207.69,
        "currency": "EUR"
      },
      "referenceNumber": "TRANSFER-34188888"
    },
    {
      "type": "CREDIT",
      "date": "2018-04-10T05:58:34.681Z",
      "amount": {
        "value": 9.94,
        "currency": "EUR"
      },
      "totalFees": {
        "value": 0,
        "currency": "EUR"
      },
      "details": {
        "type": "CONVERSION",
        "description": "Converted 8.69 GBP to 9.94 EUR",
        "sourceAmount": {
          "value": 8.69,
          "currency": "GBP"
        },
        "targetAmount": {
          "value": 9.94,
          "currency": "EUR"
        },
        "fee": {
          "value": 0.03,
          "currency": "GBP"
        },
        "rate": 1.147806
      },
      "exchangeDetails": null,
      "runningBalance": {
        "value": 9.94,
        "currency": "EUR"
      },
      "referenceNumber": "CONVERSION-1511237"
    }
  ],
  "endOfStatementBalance": {
    "value": 9.94,
    "currency": "EUR"
  },
  "query": {
    "intervalStart": "2018-03-01T00:00:00Z",
    "intervalEnd": "2018-04-30T23:59:59.999Z",
    "currency": "EUR",
    "accountId": 64
  }
}

Get borderless account statement for one currency and for specified time range. The period between intervalStart and intervalEnd cannot exceed 469 days (around 1 year 3 month).

Request

GET https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/borderless-accounts/{borderlessAccountId}/statement.json?

currency=EUR&intervalStart=2018-03-01T00:00:00.000Z&intervalEnd=2018-03-15T23:59:59.999Z&type=COMPACT

Field Description Format
borderlessAccountId Your borderlessAccountId is included in Get Account Balance response as field "id". Integer
currency Currency code Text
intervalStart Statement start time in UTC time Zulu time. Don't forget the 'Z' at the end.
intervalEnd Statement start time in UTC time Zulu time. Don't forget the 'Z' at the end.
type (optional) COMPACT (default) for a single statement line per transaction. FLAT for accounting statements where transaction fees are on a separate line. Text

Note that you can also download statements in PDF and CSV formats if you replace statement.json with statement.csv or statement.pdf respectively in the above URL.

Response

Field Description Format
accountHolder.type Account holder type: PERSONAL or BUSINESS Text
accountHolder.address.addressFirstLine Account holder address street Text
accountHolder.address.city Account holder address city Text
accountHolder.address.postCode Account holder address zipc ode Text
accountHolder.address.stateCode Account holder address state Text
accountHolder.address.countryName Account holder address country Text
accountHolder.firstName Account holder first name Text
accountHolder.lastName Account holder last name Text
issuer.name Account issuer name Text
issuer.firstLine Account issuer address street Text
issuer.city Account issuer address city Text
issuer.postCode Account issuer address zip code Text
issuer.stateCode Account issuer address state Text
issuer.country Account issuer address country Text
bankDetails Your borderless account bank details Group
transactions[n].type DEBIT or CREDIT Text
transactions[n].date Time of transaction Zulu time
transactions[n].amount.value Transaction amount Decimal
transactions[n].amount.currency Transaction currency code Text
transactions[n].totalFees.value Transaction fee amount Decimal
transactions[n].totalFees.currency Transaction fee currency code Text
transactions[n].details.type CARD, CONVERSION, DEPOSIT, TRANSFER, MONEY_ADDED Text
transactions[n].details.description Human readable explanation about the transaction Text
transactions[n].details.amount.value Amount in original currency (card transactions abroad) Decimal
transactions[n].details.amount.currency Original currency code Text
transactions[n].details.sourceAmount.value Amount in source currency (conversions) Decimal
transactions[n].details.sourceAmount.currency Source currency code Text
transactions[n].details.targetAmount.value Amount in target currency (conversions) Decimal
transactions[n].details.targetAmount.currency Target currency code Text
transactions[n].details.fee.value Conversion fee amount Decimal
transactions[n].details.fee.currency Conversion fee currency code Text
transactions[n].details.rate Conversion exchange rate Decimal
transactions[n].details.senderName Deposit sender name Text
transactions[n].details.senderAccount Deposit sender bank account details Text
transactions[n].details.paymentReference Deposit payment reference text Text
transactions[n].details.category Card transaction category Text
transactions[n].details.merchant.name Card transaction merchant name Text
transactions[n].details.merchant.firstLine Merchant address street Text
transactions[n].details.merchant.postCode Merchant address zipcode Text
transactions[n].details.merchant.city Merchant address city Text
transactions[n].details.merchant.state Merchant address state Text
transactions[n].details.merchant.country Merchant address country Text
transactions[n].details.merchant.category Merchant category Text
transactions[n].exchangeDetails.forAmount.value Currency exchange amount Decimal
transactions[n].exchangeDetails.forAmount.currency Currency code Text
transactions[n].exchangeDetails.rate Exchange rate Decimal
transactions[n].runningBalance.value Running balance after the transaction Decimal
transactions[n].runningBalance.currency Running balance currency code Text
transactions[n].referenceNumber Wise assigned unique transaction reference number Text
endOfStatementBalance.value Closing balance for specified time period Decimal
endOfStatementBalance.currency Closing balance currency code Text
query.intervalStart Query parameter repeated Zulu time
query.intervalEnd Query parameter repeated Zulu time
query.currency Query parameter repeated Text
query.accountId Query parameter repeated Integer

Convert Currencies

Example Request:

curl -X POST https://api.sandbox.transferwise.tech/v1/borderless-accounts/{borderlessAccountId}/conversions \
     -H "Authorization: Bearer <your api token>"  \
     -H "Content-Type: application/json" \
     -H "X-idempotence-uuid: <your generated uuid> \
     -d '{ 
            "quoteId": <conversion quote id>
         }'

Example Response:

{
  "id": <conversion transaction id>,
  "type": "CONVERSION",
  "state": "COMPLETED",
  "balancesAfter": [
    {
      "value": 10000594.71,
      "currency": "GBP"
    },
    {
      "value": 9998887.01,
      "currency": "EUR"
    }
  ],
  "creationTime": "2017-11-21T09:55:49.275Z",
  "steps": [
    {
      "id": 369588,
      "type": "CONVERSION",
      "creationTime": "2017-11-21T09:55:49.276Z",
      "balancesAfter": [
        {
          "value": 9998887.01,
          "currency": "EUR"
        },
        {
          "value": 10000594.71,
          "currency": "GBP"
        }
      ],
      "channelName": null,
      "channelReferenceId": null,
      "tracingReferenceCode": null,
      "sourceAmount": {
        "value": 113.48,
        "currency": "EUR"
      },
      "targetAmount": {
        "value": 100,
        "currency": "GBP"
      },
      "fee": {
        "value": 0.56,
        "currency": "EUR"
      },
      "rate": 0.88558
    }
  ],
  "sourceAmount": {
    "value": 113.48,
    "currency": "EUR"
  },
  "targetAmount": {
    "value": 100,
    "currency": "GBP"
  },
  "rate": 0.88558,
  "feeAmounts": [
    {
      "value": 0.56,
      "currency": "EUR"
    }
  ]
}

Convert funds between your borderless account currencies. Quote which is used in this call must be created with "payOut": "BALANCE".

Note that this call needs an extra field in header called "X-idempotence-uuid".

Request

POST https://api.sandbox.transferwise.tech/v1/borderless-accounts/{borderlessAccountId}/conversions

Field Description Format
borderlessAccountId Your borderlessAccountId is included in Get Account Balance response as field "id". Integer
X-idempotence-uuid Unique identifier assinged by you. Used for idempotency check purposes. Should your call fail for technical reasons then you can use the same value again for making retry call. UUID

Get Available Currencies

Example Request:

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

Example Response:

[
    {
        "code": "EUR",
        "hasBankDetails": true,
        "payInAllowed": true,
        "sampleBankDetails": null
    },
    {
        "code": "GBP",
        "hasBankDetails": true,
        "payInAllowed": true,
        "sampleBankDetails": null
    },
    {
        "code": "USD",
        "hasBankDetails": false,
        "payInAllowed": true,
        "sampleBankDetails": null
    },
...
    {
        "code": "UAH",
        "hasBankDetails": false,
        "payInAllowed": false,
        "sampleBankDetails": null
    },
    {
        "code": "ARS",
        "hasBankDetails": false,
        "payInAllowed": false,
        "sampleBankDetails": null
    },
    {
        "code": "NPR",
        "hasBankDetails": false,
        "payInAllowed": false,
        "sampleBankDetails": null
    }
]

Get list of currencies that your can hold in your borderless account. Also shows which currencies have the option to get bank account details.

Request

GET https://api.sandbox.transferwise.tech/v1/borderless-accounts/balance-currencies

Response

Field Description Format
code Currency code Text
hasBankDetails Does currency have bank details opening option Boolean
payInAllowed Can you send this currency to your borderless account Boolean
sampleBankDetails






















Get Currency Pairs

Example Request:

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

Example Response:

{
    "sourceCurrencies": [
        {
            "currencyCode": "GBP",
            "maxInvoiceAmount": 1000000,
            "targetCurrencies": [
                {
                    "currencyCode": "EUR",
                    "minInvoiceAmount": 1,
                    "fixedTargetPaymentAllowed": true
                },
                {
                    "currencyCode": "INR",
                    "minInvoiceAmount": 1,
                    "fixedTargetPaymentAllowed": true
                },
                {
                    "currencyCode": "USD",
                    "minInvoiceAmount": 1,
                    "fixedTargetPaymentAllowed": true
                },
...
                {
                    "currencyCode": "VND",
                    "minInvoiceAmount": 1,
                    "fixedTargetPaymentAllowed": true
                },
                {
                    "currencyCode": "ZAR",
                    "minInvoiceAmount": 1,
                    "fixedTargetPaymentAllowed": true
                }
            ],
            "totalTargetCurrencies": 47
        }
    ],
    "total": 19
}

Get list of allowed currency pairs that you can setup in your transfers.

Request

GET https://api.sandbox.transferwise.tech/v1/currency-pairs

Response

Field Description Format
sourceCurrencies.currencyCode Source currency code Text
sourceCurrencies.maxInvoiceAmount Maximum allowed transfer amount in source currency Decimal
targetCurrencies.currencyCode Target currency code Text
targetCurrencies.minInvoiceAmount Minimum allowed transfer amount in source currency for this pair. Decimal
targetCurrencies.fixedTargetPaymentAllowed Can you setup fixed rate payments or not. Boolean






















Comparison

Request comparison quotes

Example Request:

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

Example Response:

{
  "sourceCurrency": "GBP",
  "targetCurrency": "EUR",
  "sourceCountry": null,
  "targetCountry": null,
  "providerCountry": null,
  "providerType": null,
  "sendAmount": 10000.0,
  "providers": [
    {
      "id": 39,
      "alias": "transferwise",
      "name": "Wise",
      "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 Wise 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 % 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 collect data for all providers ~ once per hour to ensure we provide as accurate and up to date information as possible.

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://wise.com/gb/compare/disclaimer

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

comparison@wise.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 transfer should be complete within 2-5 days"
  • "The money should arrive in your account within 48 hours"
  • "Should arrive by 26th Aug"
  • "Could take up to 4 working days"

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 Wise), 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:

  • GBP EUR 1000 [GB -> ES] fee: 10, rate: 1.5
  • GBP EUR 1000 [GB -> DE] fee: 8, rate: 1.5
  • GBP EUR 1000 [GB -> FR] fee: 10, rate: 1.35

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://wise.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 Wise 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

Exchange Rates

List

Example Request (Bearer token):

curl -X GET "https://api.sandbox.transferwise.tech/v1/rates?source=EUR&target=USD" \
     -H "Authorization: Bearer <your api token>"

Example Request (Basic authentication):

curl -X GET "https://api.sandbox.transferwise.tech/v1/rates?source=EUR&target=USD" \
     --user <your api client_id>:<your api client_secret> 

Example Response:

[
    {
        "rate": 1.166,
        "source": "EUR",
        "target": "USD",
        "time": "2018-08-31T10:43:31+0000"
    }
]

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

Fetch latest exchange rates of all currencies.

GET https://api.sandbox.transferwise.tech/v1/rates?source=EUR&target=USD

Fetch latest exchange rate of one currency pair.

GET https://api.sandbox.transferwise.tech/v1/rates?source=EUR&target=USD&time=2019-02-13T14:53:01

Fetch exchange rate of specific historical timestamp.

GET https://api.sandbox.transferwise.tech/v1/rates?source=EUR&target=USD&from=2019-02-13T14:53:01&to=2019-03-13T14:53:01&group=day

Fetch exchange rate history over period of time with daily interval.

GET https://api.sandbox.transferwise.tech/v1/rates?source=EUR&target=USD&from=2019-02-13T14:53:01&to=2019-03-13T14:53:01&group=hour

Fetch exchange rate history over period of time with hourly interval.

GET https://api.sandbox.transferwise.tech/v1/rates?source=EUR&target=USD&from=2019-02-13T14:53:01&to=2019-03-13T14:53:01&group=minute

Fetch exchange rate history over period of time with 1 minute interval.

Request

Note that this endpoint supports two types of authentication: Bearer token and Basic authentication (client_id/client_secret).

Field Description Format
source Source(send) currency code. Text
target Target(receive) currency code. Text
time Timestamp to get historic exchange rate. Timestamp
from Period start date/time to get exchange rate history. Timestamp or Date
to Period end date/time to get exchange rate history. Timestamp or Date
group Interval: day hour minute Text

Response

List of exchange rate values which meet your query criteria.

Field Description Format
rate Exchange rate value. Decimal
source Source(send) currency code Text
target Target(receive) currency code Text
time Timestamp for exchange rate. Timestamp

Additional notes about date/time formatting used above

The request/response field(s) below support both Timestamp (combined date and time) and Date (date only) formats:

Field Sample
from 2019-03-13T14:53:01 or 2019-03-13
to 2019-03-13T14:53:01+0100 or 2019-03-13+0100

The request/response field(s) below support only Timestamp (combined date and time):

Field Sample
time 2019-03-13T14:53:01 or 2019-03-13T14:53:01+0100

Timezone offset is supported but optional.

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,
          "payOut": null,
          "preferredPayIn": null
        }'

Example Response:

{
    "id": "11144c35-9fe8-4c32-b7fd-d05c2a7734bf",
    "sourceCurrency": "GBP",
    "targetCurrency": "USD",
    "sourceAmount": 100,
    "payOut": "BANK_TRANSFER",
    "preferredPayIn": "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,
                "partner": 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,
                "partner": 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 Wise 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 your 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
targetAccount Optional. If provided can be used as an alternative to updating the quote. Integer
payOut Optional. Preferred payout method. Default value is BANK_TRANSFER. Other possible values are BALANCE, SWIFT and INTERAC. Text
preferredPayIn Optional. Preferred payin method. Use BANK_TRANSFER to return this method at the top of the response's results. Text

Response

The following describes the fields of the quote response that may be useful when building your integration.

The payOut field is used to select the correct entry in the paymentOptions array in order to know which fees to display to your customer. Find the paymentOption that matches the payOut field shown at the top level of the quote resource and payIn based on the settlement model the bank is using. By default this is BANK_TRANSFER, unless you are using a prefunded or bulk settlement model. The payOut field will change based on the type of recipient you add to the quote in the PATCH /quote call, for example to-USD swift_code or to-CAD interac have different fees.

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.

When showing the price of a transfer always show the total fees of a payment option.

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 received. Decimal
payOut Mechanism we use 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 created as "SOURCE" or "TARGET". Text
paymentOptions List of the methods a user can pay for the transfer. See above for help on choosing the correct one to display. [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.partner If you have agreed a custom price, it will be displayed here. 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 to 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,
                "partner": 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,
                "partner": 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 should update a quote using a PATCH call to add a recipient. This will update the saved quote's data based on who and where the money will be sent to.

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, or sending CAD over the Interac network is a more expensive operation.

When updating a quote the payOut field may change to denote the payment option you should select when sending to this recipient. For example sending USD to a swift_code recipient or CAD to an interac recipient with change payOut to SWIFT or INTERAC respectively. This field defaults to BANK_TRANSFER so it can be used in all cases to help select the correct paymentOption and hence show the correct pricing to users.

In this case, where pricing changes after a user selects recipient, you should show a message to your customer before confirming the transfer. Please see the section on Global Currencies to learn more how and why this works and the messaging you need to display.

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,
                "partner": 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,
                "partner": 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"
    }]
}

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 Wise. Text

Get Temporary Quote

Use this endpoint to get example quotes for people to see the exchange rate and fees Wise offers before a user has created or linked an account. This can drive a version of the quote screen that shows the user what Wise 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,
                "partner": 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,
                "partner": 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,
        "interacAccount": 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

  • Recipient full name
  • Legal type (private/business)
  • Currency
  • Owned by customer

Owned by customer is an optional boolean to flag to record 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 bank account in another country/currency. This field can be used to separate these recipients in your UI, however we do not recommend this as it adds unnecessary complexity to the solution. It is safe to ignore this field and display recipients with both true and false values.

2) Bank account data

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

  • GBP — sort code and account number
  • BGN, CHF, DKK, EUR, GEL, GBP, NOK, PKR, PLN, RON, SEK — IBAN
  • USD — routing number, account number, account type
  • INR — IFSC code, account number
  • etc.

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.

  • Country
  • State (US, Canada, Brazil)
  • City
  • Address line
  • Zip code

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

  • Full names for personal recipients. They must include more than one name, and both first and last name must have more than one character. Numbers are not allowed in personal recipient names.
  • Business names must be in full, but can be just a single name. The full name cannot be just a single character but can be made up of a set of single characters. e.g. "A" is not permitted but "A 1" or "A1" is permitted.
  • Special characters _()'*,. are allowed for personal and business names.
  • In general the following regex describes our permitted characters for a name: [0-9A-Za-zÀ-ÖØ-öø-ÿ-_()'*,.\s].

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 Boolean 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,
        "middleName": null,
        "patronymicName": null,
        "cannotHavePatronymicName": null
    },
    "address": {
        "country": "US",
        "firstLine": "1 Wall Street",
        "postCode": "10025",
        "city": "New York",
        "state": "NY"
    },
    "currency": "USD",
    "country": "US",
    "type": "Aba",
    "legalEntityType": "PERSON",
    "email": "example@foobar.com",
    "active": true,
    "details": {
        "abartn": "064000020",
        "accountType": "CHECKING",
        "accountNumber": "00000000001"
    },
    "commonFieldMap": {
        "accountNumberField": "accountNumber",
        "bankCodeField": "abartn"
    },
    "hash": "a512e4066bd5997552d35e294d29bacda4b09a7610a7b75562767b17dddadf19",
    "accountSummary": "(064000020) 0********01",
    "longAccountSummary": "USD account ending in 0001",
    "displayFields": [
        {
            "label": "E-mail",
            "value": "example@foobar.com"
        },
        {
            "label": "ACH routing number",
            "value": "064000020"
        },
        {
            "label": "Account number",
            "value": "00000000001"
        }
    ],
    "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 v2 endpoint provides useful features such as the accountSummary and longAccountSummary field which can be used to represent the recipient's details in your UI. Additionally, the displayFields array would allow you to build an UI containing all the dynamic fields of a recipient individually.

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.

Request

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

List

Example Request:

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

Example Response:

{
    "content": [
        {
            "id": 100,
            "creatorId": 300,
            "profileId": 305,
            "name": {
                "fullName": "Firstname Lastname",
                "givenName": null,
                "familyName": null,
                "middleName": null,
                "patronymicName": null,
                "cannotHavePatronymicName": null
            },
            "address": {
                "country": "US",
                "firstLine": "1 Wall Street",
                "postCode": "10025",
                "city": "New York",
                "state": "NY"
            },
            "currency": "USD",
            "country": "US",
            "type": "Aba",
            "legalEntityType": "PERSON",
            "email": "example@foobar.com",
            "active": true,
            "details": {
                "abartn": "064000020",
                "accountType": "CHECKING",
                "accountNumber": "00000000001"
            },
            "commonFieldMap": {
                "accountNumberField": "accountNumber",
                "bankCodeField": "abartn"
            },
            "isDefaultAccount": false,
            "hash": "a512e4066bd5997552d35e294d29bacda4b09a7610a7b75562767b17dddadf19",
            "accountSummary": "(064000020) 0********01",
            "longAccountSummary": "USD account ending in 0001",
            "displayFields": [
                {
                    "label": "E-mail",
                    "value": "example@foobar.com"
                },
                {
                    "label": "ACH routing number",
                    "value": "064000020"
                },
                {
                    "label": "Account number",
                    "value": "00000000001"
                }
            ],
            "ownedByCustomer": false
        },
        {
            "id": 101,
            "creatorId": 300,
            "profileId": 305,
            "name": {
                "fullName": "Firstname Anothername",
                "givenName": null,
                "familyName": null,
                "middleName": null,
                "patronymicName": null,
                "cannotHavePatronymicName": null
            },
            "address": {
                "country": "US",
                "firstLine": "1 Wall Street",
                "postCode": "10025",
                "city": "New York",
                "state": "NY"
            },
            "currency": "USD",
            "country": "US",
            "type": "Aba",
            "legalEntityType": "PERSON",
            "email": "example2@foobar.com",
            "active": true,
            "details": {
                "abartn": "064000020",
                "accountType": "CHECKING",
                "accountNumber": "00000000001"
            },
            "commonFieldMap": {
                "accountNumberField": "accountNumber",
                "bankCodeField": "abartn"
            },
            "isDefaultAccount": false,
            "hash": "992ca6102a11f2055d14682e0cbacd65727fc45e98b1c42ba1292acad08302c5",
            "accountSummary": "(064000020) 0********01",
            "longAccountSummary": "USD account ending in 0001",
            "displayFields": [
                {
                    "label": "E-mail",
                    "value": "example2@foobar.com"
                },
                {
                    "label": "ACH routing number",
                    "value": "064000020"
                },
                {
                    "label": "Account number",
                    "value": "00000000002"
                }
            ],
            "ownedByCustomer": false
        }
    ],
    "sort": {
        "sorted": false,
        "unsorted": true,
        "empty": 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, based on your use case. Other filters are listed below for your convenience, for example currency is a useful filter to use when presenting the user a list of recipients to chose from in the case they have already submitted the target currency of their in your flow.

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,swift_code). 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>"

Example Response:

{
    "id": 101,
    "creatorId": 300,
    "profileId": 305,
    "name": {
        "fullName": "Firstname Anothername",
        "givenName": null,
        "familyName": null,
        "middleName": null,
        "patronymicName": null,
        "cannotHavePatronymicName": null
    },
    "address": {
        "country": "US",
        "firstLine": "1 Wall Street",
        "postCode": "10025",
        "city": "New York",
        "state": "NY"
    },
    "currency": "USD",
    "country": "US",
    "type": "Aba",
    "legalEntityType": "PERSON",
    "email": "example2@foobar.com",
    "active": false,
    "details": {
        "abartn": "064000020",
        "accountType": "CHECKING",
        "accountNumber": "00000000001"
    },
    "commonFieldMap": {
        "accountNumberField": "accountNumber",
        "bankCodeField": "abartn"
    },
    "isDefaultAccount": false,
    "hash": "992ca6102a11f2055d14682e0cbacd65727fc45e98b1c42ba1292acad08302c5",
    "accountSummary": "(064000020) 0********01",
    "longAccountSummary": "USD account ending in 0001",
    "displayFields": [
        {
            "label": "E-mail",
            "value": "example2@foobar.com"
        },
        {
            "label": "ACH routing number",
            "value": "064000020"
        },
        {
            "label": "Account number",
            "value": "00000000002"
        }
    ],
    "ownedByCustomer": false
}

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

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 version 1.1

Example Request:

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

Example Response:

[
    {
        "type": "south_korean_paygate",
        "title": "PayGate",
        "usageInfo": null,
        "fields": [
            {
                "name": "E-mail",
                "group": [
                    {
                        "key": "email",
                        "name": "E-mail",
                        "type": "text",
                        "refreshRequirementsOnChange": false,
                        "required": true,
                        "displayFormat": null,
                        "example": "example@example.ex",
                        "minLength": null,
                        "maxLength": null,
                        "validationRegexp": "^[^\\s]+@[^\\s]+\\.[^\\s]{2,}$",
                        "validationAsync": null,
                        "valuesAllowed": null
                    }
                ]
            },
            {
                "name": "Recipient type",
                "group": [
                    {
                        "key": "legalType",
                        "name": "Recipient type",
                        "type": "select",
                        "refreshRequirementsOnChange": false,
                        "required": true,
                        "displayFormat": null,
                        "example": "",
                        "minLength": null,
                        "maxLength": null,
                        "validationRegexp": null,
                        "validationAsync": null,
                        "valuesAllowed": [
                            {
                                "key": "PRIVATE",
                                "name": "Person"
                            }
                        ]
                    }
                ]
            },
            {
                "name": "Full Name",
                "group": [
                    {
                        "key": "accountHolderName",
                        "name": "Full Name",
                        "type": "text",
                        "refreshRequirementsOnChange": false,
                        "required": true,
                        "displayFormat": null,
                        "example": "",
                        "minLength": 2,
                        "maxLength": 140,
                        "validationRegexp": "^[0-9A-Za-zÀ-ÖØ-öø-ÿ-_()'*,.%#^@{}~<>+$\"\\[\\]\\\\ ]+$",
                        "validationAsync": null,
                        "valuesAllowed": null
                    }
                ]
            },
            {
                "name": "Recipient's Date of Birth",
                "group": [
                    {
                        "key": "dateOfBirth",
                        "name": "Recipient's Date of Birth",
                        "type": "date",
                        "refreshRequirementsOnChange": false,
                        "required": true,
                        "displayFormat": null,
                        "example": "",
                        "minLength": null,
                        "maxLength": null,
                        "validationRegexp": "^\\d{4}\\-\\d{2}\\-\\d{2}$",
                        "validationAsync": null,
                        "valuesAllowed": null
                    }
                ]
            },
            {
                "name": "Recipient Bank Name",
                "group": [
                    {
                        "key": "bankCode",
                        "name": "Recipient Bank Name",
                        "type": "select",
                        "refreshRequirementsOnChange": false,
                        "required": true,
                        "displayFormat": null,
                        "example": "Choose recipient bank",
                        "minLength": null,
                        "maxLength": null,
                        "validationRegexp": null,
                        "validationAsync": null,
                        "valuesAllowed": [
                            {
                                "key": "",
                                "name": "Choose recipient bank"
                            },
                            ...
                        ]
                    }
                ]
            },
            {
                "name": "Account number (KRW accounts only)",
                "group": [
                    {
                        "key": "accountNumber",
                        "name": "Account number (KRW accounts only)",
                        "type": "text",
                        "refreshRequirementsOnChange": false,
                        "required": true,
                        "displayFormat": null,
                        "example": "1254693521232",
                        "minLength": 10,
                        "maxLength": 16,
                        "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
GET https://api.sandbox.transferwise.tech/v1/account-requirements?source=EUR&target=USD&sourceAmount=1000

This incremental version of GET and POST account requirements enables you to fetch requirements which include both recipient name and email fields in the dynamic form. This is needed for appropriate requirements addressing of recipients for currencies like KRW, JPY and RUB, and simplifies the implementation of the dynamic form as it removes the need for manual name validation. To address the incremental 1.1 version of the endpoint you’ll be required to add the Accept-Minor-Version header.

The third sample shows how to get account requirements for a specific currency route without referring to a particular quote but with the amount, source and target currencies passed as URL parameters.

These endpoints support use of both v1 and v2 quotes using long or UUID based IDs.

Requirements

Example Request:

curl -X GET https://api.sandbox.transferwise.tech/v1/quotes/{quoteId|quoteUuid}/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://api.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://api.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|quoteUuid}/account-requirements
POST https://api.sandbox.transferwise.tech/v1/quotes/{quoteId|quoteUuid}/account-requirements
GET https://api.sandbox.transferwise.tech/v1/account-requirements?source=EUR&target=USD&sourceAmount=1000

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.

The third sample shows how to get account requirements for a specific currency route without referring to a particular quote but with the amount, source and target currencies passed as URL parameters.

These endpoints support use of both v1 and v2 quotes using long or UUID based IDs.

Using account requirements

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

2.Call GET /v1/quotes/{quoteId|quoteUuid}/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:

  • legalType (PRIVATE / BUSINESS)
  • abartn (ABA routing number)
  • accountType (CHECKING / SAVINGS)
  • address.country
  • address.city
  • address.postalCode
  • address.firstLine

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|quoteuuid}/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 Wise platform. If you wish to do this you can include the parameter &addressRequired=true in your call to GET /v1/quotes/{quoteId/quoteUuid}/account-requirements, if this is present we will return address fields as part of the form.

Building a user interface

Account requirements help us understand how to create a valid account given a certain context. As a tool to help explore this API, please visit Dynamic Forms UI. This app allows specifying different requests and calls our sandbox environment for account requirements. It then displays the response in JSON along with an example of the rendered form from the said response.

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 max 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.

Some good recipient currencies to test are:

  • CAD - has several fields in a field group.
  • USD - the country field has refreshRequirementsOnChange.
  • JPY - the bank field has refreshRequirementsOnChange.
  • PEN - has a field using a date component type.

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

Create Refund Recipient

Sometimes we may need to refund the transfer's funds - see the transfer status here for cases when this may happen.

A refund recipient is a person or institution where we will refund transfer funds to. This is not a mandatory step if the bank is using a fast local payment network as we can usually infer the refund recipient from the bank transaction that funded the transfer.

But if the bank is using a slow domestic payment network and a "prefunded" model, we may try to refund before we receive the funds in our bank transactions. In these instances, we require you to inform us what are the details where to refund transfers. In order to do this we have the following API:

Example Request (Create GBP refund recipient):

curl -X POST https://api.sandbox.transferwise.tech/v2/accounts?isRefund=true \
     -H "Authorization: Bearer <your api token>" \
     -H "Content-Type: application/json" \
     -d '{
          "currency": "GBP",
          "country": "GB",
          "type": "sort_code",
          "profile": <your profile id>,
          "legalEntityType": "PERSON",
          "name": {
              "fullName": "Ann Johnson"
          },
          "details": {              
              "sortCode": "231470",
              "accountNumber": "28821822"
          }
         }'

Example Response (Create GBP refund recipient):

{
    "id": 13967081,
    "creatorId": <your user ID>,
    "name": {
        "fullName": "Ann Johnson",
        "givenName": null,
        "familyName": null,
        "middleName": null,
        "patronymicName": null,
        "cannotHavePatronymicName": null
    },
    "currency": "GBP",
    "country": "GB",
    "type": "SortCode",
    "legalEntityType": "PERSON",
    "active": true,
    "details": {
        "accountNumber": "28821822",
        "sortCode": "231470"
    },
    "commonFieldMap": {
        "accountNumberField": "accountNumber",
        "bankCodeField": "sortCode"
    },
    "hash": "abd0e73e6497e678f20cd5d5d700c8926d47d3dae23e092ef45a904455bd70e1",
    "accountSummary": "(23-14-70) 28821822",
    "longAccountSummary": "GBP account ending in 0000",
    "displayFields": [
        {
            "label": "UK Sort code",
            "value": "23-14-70"
        },
        {
            "label": "Account number",
            "value": "28821822"
        }
    ],
    "ownedByCustomer": false
}

The refund recipient account id returned here is needed when creating transfers in step 3 as the field sourceAccount.

The format of the request payload for refund recipient creation will be different depending on the currency you will send transfers from. The above example is for GBP only. We can provide the correct format for your bank upon request.

Create Email Recipient

Example Request (Create email recipient):

curl -X POST https://api.sandbox.transferwise.tech/v1/accounts \
     -H "Authorization: Bearer <your api token>" \
     -H "Content-Type: application/json" \
     -d '{ 
          "profile": <your profile id>, 
          "accountHolderName": "Ann Johnson",
          "currency": "EUR", 
          "type": "email", 
           "details": { 
              "email": "ann.johnson@gmail.com"
           } 
         }'

Example Response (Lookup email recipient):

{
    "id": 13967196,
    "business": null,
    "profile": <your profile id>,
    "accountHolderName": "Ann Johnson",
    "currency": "EUR",
    "country": null,
    "type": "email",
    "details": {
        "address": {
            "country": null,
            "countryCode": null,
            "firstLine": null,
            "postCode": null,
            "city": null,
            "state": null
        },
        "email": "ann.johnson@gmail.com",
        "legalType": "PRIVATE",
        "accountNumber": null,
        "sortCode": null,
        "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,
        "interacAccount": null
    },
    "user": <your user id>,
    "active": true,
    "ownedByCustomer": false
}

If you don't know recipient bank account details you can set up an email recipient; Wise will collect bank details directly from the recipient.

Wise will email your recipient with a link to collect their bank account details securely. After the bank account details have been provided Wise will complete your transfer.

Please be aware of the following caveats:

  • Testing of transfers to email recipients in sandbox is not currently possible.
  • Recipients will be required to enter bank details every time a payment is made.
  • Please refer to our help page on how this works and any additional constraints not mentioned in this section.

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.

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 Wise terms and conditions in HTML format to show to your customers who are signing up for their Wise account. This endpoint is applicable for bank integrations and third party application integrators only.

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.

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 '{ 
          "sourceAccount": <refund recipient account id>,   
          "targetAccount": <recipient account id>,   
          "quoteUuid": <v2 quote id>,
          "customerTransactionId": "<the unique identifier 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": null,
    "quoteUuid": <v2 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"
}

A transfer is a payment 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 be automatically canceled.

Request

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

Field Description Format
sourceAccount (optional) Refund recipient account id. Integer
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.
Text
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 80k. See more about conditions at Transfers.Requirements Text

There are two options to deal with conditionally required fields:

  • Always provide values for these fields
  • Always call transfers-requirements endpoint and submit values only if indicated so.

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 Refund recipient account id Integer
quote v1 quote id (where applicable) Integer
quoteUuid v2 quote id Text
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 Unique identifier randomly generated per transfer request by the calling client 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.

Fund

Example Request:

curl -X POST https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/transfers/{transferId}/payments \
     -H "Authorization: Bearer <your api token>" \
     -H "Content-Type: application/json" \
     -d '{ 
          "type": "BALANCE"   
         }'

Example Response:

{
  "type": "BALANCE",
  "status": "COMPLETED",
  "errorCode": null
}

This API call is the final step for executing payouts. TransferWise will now debit funds from your borderless balance and start processing your transfer. If your borderless balance is short of funds then this call will fail with "insufficient funds" error.

Request

POST https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/transfers/{transferId}/payments

Use transfer id that you obtained in previous step.

Field Description Format
type "BALANCE".
This indicates that your transfer will be funded from your borderless account balance.
Text

Response

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

Field Description Format
type "BALANCE" Text
status "COMPLETED" or "REJECTED" Text
errorCode Failure reason. For example "balance.payment-option-unavailable" Text

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": "Testing"
  },
  "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 Refund recipient account id 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 Unique identifier randomly generated per transfer request by the calling client 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 Refund recipient account id 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 Unique identifier randomly generated per transfer request by the calling client 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 beneficiary'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:

    • all failed payments created since last week
    • all completed payments created since yesterday

    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 Refund recipient account id 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 Unique identifier assigned 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 its own specific nuances when it comes to the nitty gritty details of domestic payment systems and money transfer regulations. The 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.

    The same is true for requirements arising from Anti-Money Laundering regulations adopted in different countries. Depending on the chosen currencies and the amount transfer, either in one go or cumulatively over time, Wise may require more details about the customer's source of funds or transfer purpose, for example.

    The endpoint /transfer-requirements exposes all these specific requirements based on the specific quote and selected target recipient account.

    To make sure that processing of your customer's transfers does not get delayed because of missing details, we highly recommend to verify the transfer requirements before before submitting any transfer and collecting the data we request from the user using the returned dynamic form.

    Request

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

    1.Prepare the request body to create transfer object first. Now post this request body to the 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




































    Third-Party Transfers

    Create

    Example Request (Originator Type = PRIVATE):

    curl -X POST https://api.sandbox.transferwise.tech/v2/profiles/{profileId}/third-party-transfers \
         -H "Authorization: Bearer <your api token>" \
         -H "Content-Type: application/json" \
         -d '{ 
              "targetAccount": <recipient account id>,   
              "quoteUuid": "<v2 quote id>",
              "originalTransferId": "<unique transfer id in your system>",
              "details" : {
                  "reference" : "Ski trip"
              },
              "originator" : {
                  "legalEntityType" : "PRIVATE",
                  "reference" : "<unique customer id in your system>",
                  "name" : {
                    "givenName": "John",
                    "middleNames": ["Ryan"],
                    "familyName": "Godspeed"
                  },
                  "dateOfBirth": "1977-07-01",
                  "address" : {
                    "firstLine": "Salu tee 100, Apt 4B",
                    "city": "Tallinn",
                    "countryCode": "EE",
                    "postCode": "12112"
                  }
              } 
             }'

    Example Request (Originator Type = BUSINESS):

    curl -X POST https://api.sandbox.transferwise.tech/v2/profiles/{profileId}/third-party-transfers \
         -H "Authorization: Bearer <your api token>" \
         -H "Content-Type: application/json" \
         -d '{ 
              "targetAccount": <recipient account id>,   
              "quoteUuid": "<v2 quote id>",
              "originalTransferId": "<unique transfer id in your system>",
              "details" : {
                  "reference" : "Payment for invoice 22092"
              },
              "originator" : {
                  "legalEntityType" : "BUSINESS",
                  "reference" : "<originator customer id in your system>",
                  "name" : {
                    "fullName": "Hot Air Balloon Services Ltd"
                  },
                  "businessRegistrationCode": "1999212",
                  "address" : {
                    "firstLine": "Aiandi tee 1431",
                    "city": "Tallinn",
                    "countryCode": "EE",
                    "postCode": "12112"
                  }
              } 
           }'

    Example Response:

    
    {
        "id": 47755772,
        "originalTransferId": "PMT-29991221",
        "user": <your user id>,
        "targetAccount": <recipient account id>,
        "quote": null,
        "quoteUuid": "<v2 quote id>",
        "status": "incoming_payment_waiting",
        "rate": 0.8762,
        "details": {
            "reference": "Ski trip"
        },
        "hasActiveIssues": false,
        "sourceCurrency": "EUR",
        "sourceValue": 0,
        "targetCurrency": "GBP",
        "targetValue": 500,
        "originator": {
            "name": {
                "givenName": "John",
                "middleNames": [
                    "Ryan"
                ],
                "familyName": "Godspeed",
                "patronymicName": null,
                "fullName": "John Godspeed"
            },
            "dateOfBirth": "1977-07-01",
            "reference": "CST-2991992",
            "legalEntityType": "PRIVATE",
            "businessRegistrationCode": null,
            "address": {
                "firstLine": "Salu tee 14",
                "city": "Tallinn",
                "stateCode": null,
                "countryCode": "EE",
                "postCode": "12112"
            }
        },
        "created": "2019-02-18T12:59:42.000Z"
    }
    

    This endpoint is applicable for Third-Party Payouts use case only.

    Request

    POST https://api.sandbox.transferwise.tech/v2/profiles/{profileId}/third-party-transfers

    This is very similar to Create transfers endpoint, but please note these differences:

    • originator datablock is additionally required
    • originalTransferId field is being used instead of customerTransactionId
    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.
    Text
    originalTransferId Unique transfer id in your system. We use this field also to perform idempotency check to avoid duplicate transfers in case of network failures or timeouts. You can only submit one transfer with same originalTransferId. Text
    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
    originator Data block to capture payment originator details. Group
    originator.legalEntityType PRIVATE or BUSINESS. Payment originator legal type. Text
    originator.reference Unique customer id in your system. This allows us to uniquely identify each originator. Required. Text
    originator.name.givenName Payment originator first name. Required if legalEntityType = PRIVATE. Text
    originator.name.middleNames Payment originator middle name(s). Used only if legalEntityType = PRIVATE. Optional Text Array
    originator.name.familyName Payment originator family name. Required if legalEntityType = PRIVATE. Text
    originator.name.patronymicName Payment originator patronymic name. Used only if legalEntityType = PRIVATE. Optional Text
    originator.name.fullName Payment originator full legal name. Required if legalEntityType = BUSINESS. Text
    originator.dateOfBirth Payment originator date of birth. Required if legalEntityType = PRIVATE. YYYY-MM-DD
    originator.businessRegistrationCode Payment originator business registry number / incorporation number. Required if legalEntityType = BUSINESS. Text
    originator.address.firstLine Payment originator address first line. Required Text
    originator.address.city Payment originator address city. Required Text
    originator.address.stateCode Payment originator address state code. Required if address country code in (US, CA, BR, AU). See Countries and states Text
    originator.address.countryCode Payment originator address first line. Required Text
    originator.address.postCode Originator address zip code. Optional Text

    Response

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

    Field Description Format
    id Transfer id Integer
    originalTransferId Transfer id Integer
    user Your user id Integer
    targetAccount Recipient account id Integer
    sourceAccount Not used Integer
    quote v1 quote id (where applicable) Integer
    quoteUuid v2 quote id Text
    status Transfer current status Text
    rate Exchange rate value Decimal
    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
    originator Data block to capture payment originator details Group
    originator.legalEntityType Payment originator legal type. Text
    originator.reference Unique customer id in your system. Text
    originator.name.givenName Payment originator first name. Text
    originator.name.middleNames Payment originator middle name(s). Text Array
    originator.name.familyName Payment originator family name. Text
    originator.name.patronymicName Payment originator patronymic name. Text
    originator.name.fullName Payment originator full legal name. Text
    originator.dateOfBirth Payment originator date of birth. YYYY-MM-DD
    originator.businessRegistrationCode Payment originator business registry number / incorporation number. Text
    originator.address.firstLine Payment originator address first line. Text
    originator.address.city Payment originator address city. Text
    originator.address.stateCode Payment originator address state code. Text
    originator.address.countryCode Payment originator address first line. Text
    originator.address.postCode Originator address zip code. Text
    created Timestamp when transfer was created Timestamp

    Avoiding duplicate transfers

    We use originalTransferId field to avoid duplicate transfer requests. When your first call fails (error or timeout) then you should use the same value in originalTransferId field that you used in the original call when you are submitting a retry message. This way we can treat subsequent retry messages as repeat messages and will not create duplicate transfers to your account.

    Managing third-party transfers

    Please refer to our Transfers section.

    Fund

    Please refer to our Transfer Fund section.

    Batch Groups

    A batch group is a named collection of transfers that can be managed as a single unit. Batch groups are primarily used for funding multiple transfers with a single pay in.

    The Batch Group resource

    Example batch group resource with bank transfer pay in details

    {
        "id": "54a6bc09-cef9-49a8-9041-f1f0c654cd89",
        "version": 123,
        "name": "My batch group",
        "sourceCurrency": "GBP",
        "status": "COMPLETED",
        "transferIds": [
            123,
            456
        ],
        "payInDetails": [
            {
                "type": "bank_transfer",
                "reference": "B123",
                "amount": 123.45,
                "currency": "GBP",
                "name": "Wise",
                "bankCode": "231470",
                "accountNumber": "77643994",
                "iban": null
            }
        ]
    }

    Example batch group resource with additional details (USD source currency):

    {
        "id": "54a6bc09-cef9-49a8-9041-f1f0c654cd89",
        "version": 123,
        "name": "My batch group",
        "sourceCurrency": "USD",
        "status": "COMPLETED",
        "transferIds": [
            123,
            456
        ],
        "payInDetails": [
            {
                "type": "bank_transfer",
                "reference": "B123",
                "amount": 123.45,
                "currency": "USD",
                "name": "Wise Inc",
                "bankCode": "091000019",
                "bankAddress": {
                    "name": "Some Bank",
                    "firstLine": "1 Some Street",
                    "postCode": "10001",
                    "city": "Some City",
                    "stateCode": "NY",
                    "country": "US"
                },
                "accountNumber": "123456789012",
                "accountType": "checking",
                "iban": null,
                "transferWiseAddress": {
                    "name": "Wise Inc",
                    "firstLine": "19 W 24th Street Floor 9",
                    "postCode": "10010",
                    "city": "New York",
                    "country": "United States",
                    "stateCode": "NY"
                }
            }
        ]
    }

    Example batch group resource with additional details (NOK source currency):

    {
        "id": "54a6bc09-cef9-49a8-9041-f1f0c654cd89",
        "version": 123,
        "name": "My batch group",
        "sourceCurrency": "NOK",
        "status": "COMPLETED",
        "transferIds": [
            234,
            456
        ],
        "payInDetails": [
            {
                "type": "bank_transfer",
                "reference": "B5323",
                "amount": 12504.54,
                "currency": "NOK",
                "name": "TransferWise Ltd",
                "bankCode": "8301",
                "bankAddress": {
                    "name": "CitiBank Europe Plc",
                    "firstLine": "Bolette brygge 1",
                    "postCode": "0252",
                    "city": "Oslo",
                    "country": "Norway",
                    "stateCode": null
                },
                "transferWiseAddress": {
                    "name": "TransferWise Ltd",
                    "firstLine": "6th Floor, The Tea Building, 56 Shoreditch High Street",
                    "postCode": "E1 6JJ",
                    "city": "London",
                    "country": "United Kingdom",
                    "stateCode": null
                },
                "accountNumber": "9910728",
                "iban": null,
                "bban": "83019910728"
            }
        ]
    }

    Example batch group resource with additional details (HKD source currency):

    {
        "id": "54a6bc09-cef9-49a8-9041-f1f0c654cd89",
        "version": 123,
        "name": "My batch group",
        "sourceCurrency": "HKD",
        "status": "COMPLETED",
        "transferIds": [
            234,
            456
        ],
        "payInDetails": [
            {
                "type": "bank_transfer",
                "reference": "B5323",
                "amount": 12504.54,
                "currency": "NOK",
                "name": "TransferWise Ltd",
                "bankCode": "8301",
                "bankAddress": {
                    "name": "DBS Bank Hong Kong Limited",
                    "firstLine": "99 Queen's Road Central",
                    "postCode": null,
                    "city": "Central",
                    "country": "Hong Kong",
                    "stateCode": null
                },
                "accountNumber": "478000216470",
                "iban": null,
                "fpsIdentifier": "hkd@wise.com"
            }
        ]
    }

    Many Batch Group API endpoints return a batch group resource. Batch group resources have the following properties:

    Field Description Format
    id Unique batch group ID. Text
    version Batch version, used for concurrency control. This number is updated whenever there is a change to the batch group state (its status, the identity of the transfers in the batch, etc).

    Some API operations will require this version in requests, and operations may be rejected when the requested version does not match the server’s version.

    The version will be a signed integer and is not ordered with respect to any previous version.
    Integer
    name Descriptive name. Text
    sourceCurrency Source currency as a three-character ISO 4217 currency code. This the currency expected to be used for funding the batch group. Text
    status Current Batch Group Status (see below). Text
    transferIds The IDs of all transfers successfully added to the group. Array
    payInDetails List of pay in details (see Pay In Details below). Provided only when the batch-group is in the COMPLETED state. Array

    Batch Group Status

    Status Description
    NEW New batch group with zero or more transfers. Able to have more transfers added to it. Any transfers in a NEW group cannot be yet be funded and paid out.
    COMPLETED The batch group has had all the desired transfers added to it and is now closed to further changes. The transfers in the group are now able to be funded and paid out.

    Note: COMPLETED does not imply that payouts have been successfully completed. It means that all required transfers have been created and associated with the batch group.
    MARKED_FOR_CANCELLATION Cancellation of the transfers in the batch group was requested.
    PROCESSING_CANCEL Transfers in the group are being cancelled. This takes time in Wise's system.
    CANCELLED Transfers in the group have been cancelled.

    Pay In Details

    Pay In Details describe how the batch group can be funded. They are only populated when a batch group is in the COMPLETED state.

    The following fields are always populated:

    Field Description Format
    type Method of payment. Currently supported types: bank_transfer. Text
    reference The reference that should be used when funding the transfers in the batch group. This reference should be treated as an opaque value and there should be no attempt to decode or decompose it. Text
    amount The total pay in amount for all transactions in the batch when paying-in with this reference and method. Decimal
    currency Three-character ISO 4217 currency code. Text

    These fields are populated when type is bank_transfer:

    Field Description Format
    name Name of the bank account holder. Text
    accountNumber Bank account number. Text
    accountType The Bank Account Type, provided only when the currency route requires it. Text
    bankCode Bank identifier or routing number, depending on pay in type and currency (see Pay In Details Bank Codes for details). Text
    bankAddress The Pay In Details Address for the receiving bank, provided only when the currency route requires it. Object
    transferWiseAddress Wise's Pay In Details Address, provided only when the currency route requires it. Object
    iban ISO 13616 International Bank Account Number (when available). Text
    bban Basic Bank Account Number (BBAN). Provided only when the currency route requires it (such as NOK). Text
    institutionNumber Financial Institution number (3 digits). Provided only when the currency route requires it (such as CAD). Text
    transitNumber Branch Transit Number (5 digits). Provided only when the currency route requires it (such as CAD). Text
    beneficiaryBankBIC Beneficiary Bank Business Identifier Code (BIC). Provided only when the currency route requires it (such as CAD). Text
    intermediaryBankBIC Intermediary Bank Business Identifier Code (BIC). Provided only when the currency route requires it (such as CAD). Text
    fpsIdentifier Faster Payment System identifier. Provided only when the currency route requires it (such as HKD). Text

    Pay In Details Account Type

    Account type Account type Currencies
    checking Checking account USD

    Pay In Details Bank Codes

    Pay in type Currency Bank code Example
    bank_transfer GBP Sort code 565777
      USD ABA routing number 021000021
      NOK Bank code 8301
      SGD Bank code 7171
      HKD Clearing code 016
      AUD BSB (bank state branch) 182-512

    Pay In Details Address

    Bank transfer pay in details may contain bank and Wise's addresses for some source currencies.

    These currencies include: USD, NOK.

    Field Description Format
    name Bank name / Wise's company name Text
    firstLine Street address Text
    postCode Postcode / ZIP code Text
    city City Text
    stateCode State, province or region code Text (format depends on country)
    country Country code 2 character ISO 3316 country code

    Create Batch Group

    Create a new batch group.

    Example Request:

    curl -X POST https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/batch-groups \
         -H "Authorization: Bearer <your api token>" \
         -H "Content-Type: application/json" \
         -d '{
               "sourceCurrency": "GBP",
               "name": "my-batch-group"
             }'

    Example Response:

    {
      "id": "54a6bc09-cef9-49a8-9041-f1f0c654cd88",
      "version": 0,
      "name": "my-batch-group",
      "sourceCurrency": "GBP",
      "status": "NEW",
      "transferIds": [],
      "payInDetails": []
    }

    Request

    POST https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/batch-groups

    Field Description Format
    sourceCurrency ISO 4217 currency code used as the source currency for all transfers in the batch group. Text
    name Descriptive name for display purposes, recommended to use a name that uniquely represents this batch. Maximum length of 100 characters. Text

    Response

    A batch group resource.

    Error responses

    See errors page for a general description of API error responses. For all requests “401 Unauthorized” and 5xx series errors are possible.

    HTTP status Reason
    400 Bad Request - Missing sourceCurrency
    - Invalid sourceCurrency

    Get Batch Group

    Get an existing batch group.

    Example Request:

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

    Example Response:

    {
        "id": "54a6bc09-cef9-49a8-9041-f1f0c654cd88",
        "version": 1234,
        "name": "my-batch-group",
        "sourceCurrency": "GBP",
        "status": "NEW",
        "transferIds": [
            123,
            456
        ],
        "payInDetails": []
    }

    Request

    GET https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/batch-groups/{batchGroupId}

    Field Description Format
    profileId The profile that the batch group is associated with. Number
    batchGroupId The batch group ID. Text

    Response

    A batch group resource.

    Error responses

    See errors page for a general description of API error responses. For all requests “401 Unauthorized” and 5xx series errors are possible.

    HTTP status Reason
    404 Not Found Requested group does not exist or is not visible to the requesting profile

    Create Batch Group Transfer

    Create a transfer in the batch group, using a previously created recipient account and quote. Please see v2 quote creation and recipient account creation documentation.

    Example Request:

    curl -X POST https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/batch-groups/{batchGroupId}/transfers \
         -H "Authorization: Bearer <your api token>" \
         -H "Content-Type: application/json" \
         -d '{
               <transfer properties>
             }'

    Request

    POST https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/batch-groups/{batchGroupId}/transfers

    For the request body format please see this documentation.

    Response

    Please see the documentation.

    Error responses

    See errors page for a general description of API error responses. For all requests “401 Unauthorized” and 5xx series errors are possible.

    HTTP status Reason
    400 Bad Request Missing / invalid request arguments
    422 Unprocessable Entity - Attempt to create transfer using a quote already used for another transfer
    - Attempt to create transfer for a missing/inaccessible target account

    Complete Batch Group

    Completes the batch group and allows funding to proceed. Note: this action prevents any further modification.

    Example Request:

    curl -X PATCH https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/batch-groups/{batchGroupId} \
         -H "Authorization: Bearer <your api token>" \
         -H "Content-Type: application/json" \
         -d '{
               "status": "COMPLETED",
               "version": 1234
             }'

    Example Response:

    {
        "id": "54a6bc09-cef9-49a8-9041-f1f0c654cd88",
        "version": 1234,
        "name": "my-batch-group",
        "sourceCurrency": "GBP",
        "status": "COMPLETED",
        "transferIds": [
            123,
            456
        ],
        "payInDetails": [
            {
                "type": "bank_transfer",
                "reference": "XYZ123",
                "amount": 123.45,
                "currency": "GBP",
                "name": "Wise",
                "bankCode": "231470",
                "accountNumber": "77643994",
                "iban": null
            }
        ]
    }

    Request

    PATCH https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/batch-groups/{batchGroupId}

    Field Description Format
    profileId The profile that the batch group is associated with. Number
    batchGroupId The batch group ID. Text
    version The expected batch group version. This is a concurrency control mechanism. For the change to be accepted by the server, the expected version of the group must match the current version held by the server.

    Versions are discovered by requesting batch group resources.
    UUID

    Response

    A batch group resource.

    Error responses

    See errors page for a general description of API error responses. For all requests “401 Unauthorized” and 5xx series errors are possible.

    HTTP status Reason
    400 Bad Request Missing / invalid request arguments
    409 Conflict Group version mismatch (the group has been modified since the requested version)
    422 Unprocessable Entity Invalid state transition (e.g. from COMPLETED to NEW)

    Cancel Batch Group

    Cancel a batch group. Cancelling closes the group to further modification and initiates the cancellation of all transfers in the batch group. Only batches that are not funded can be cancelled. Cancellation is final it cannot be undone.

    Example Request:

    curl -X PATCH https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/batch-groups/{batchGroupId} \
         -H "Authorization: Bearer <your api token>" \
         -H "Content-Type: application/json" \
         -d '{
              "status": "CANCELLED",
              "version": 1234
            }'

    Example Response:

    {
        "id": "54a6bc09-cef9-49a8-9041-f1f0c654cd88",
        "version": 12345,
        "name": "my-batch-group",
        "sourceCurrency": "GBP",
        "status": "MARKED_FOR_CANCELLATION",
        "transferIds": [
            123,
            456
        ],
        "payInReferences": []
    }

    Request

    PATCH https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/batch-groups/{batchGroupId}

    Field Description Format
    profileId The profile that the batch group is associated with. Number
    batchGroupId The batch group ID. Text
    version The expected batch group version. This is a concurrency control mechanism. For the change to be accepted by the server, the expected version of the group must match the current version held by the server.

    Versions are discovered by requesting batch group resources.
    UUID

    Response

    A batch group resource.

    Error responses

    See errors page for a general description of API error responses. For all requests “401 Unauthorized” and 5xx series errors are possible.

    HTTP status Reason
    400 Bad Request Missing / invalid request arguments
    409 Conflict Group version mismatch (the group has been modified since the requested version)
    422 Unprocessable Entity Invalid state transition

    Fund Batch Group

    Funds all the transfers in a batch, they are paid out immediately. Applicable when funding from a multi-currency account ("a balance"). The Batch Group must first be completed, and there needs to be enough funds in the account for the whole batch (insufficient funds will return an error).

    This endpoint is SCA protected when it applies, you can find more info here.

    Example Request:

    curl -X POST https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/batch-payments/{batchGroupId}/payments \
         -H "Authorization: Bearer <your api token>" \
         -H "Content-Type: application/json" \
         -d '{
               "type": "BALANCE"
             }'

    Example Response:

    {
        "id": "54a6bc09-cef9-49a8-9041-f1f0c654cd88",
        "name": "my-batch-group",
        "fileName": null,
        "alreadyPaid": true,
        "shortId": 12345,
        "userId": 123,
        "profileId": 56789,
        "sourceCurrency": "GBP",
        "status": "COMPLETED",
        "groupType": "API",
        "transferIds": [
          123,
          456
        ]
    }

    Request

    POST https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/batch-payments/{batchGroupId}/payments

    Field Description Format
    type The method of payment to use (must always be BALANCE) Text

    Response

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

    Field Description Format
    id Unique batch group ID. Text
    name Descriptive name. Text
    fileName If this batch was submitted as a file, this is the given file name Text
    alreadyPaid This field is not applicable to this use case Boolean
    shortId This field is not applicable to this use case Number
    userId The ID of the user who initiated this payment Number
    profileId The ID of the profile this payment belongs to Number
    sourceCurrency The source currency of the batch (note: we will prefer this currency but if there are insufficient funds then an automatic conversion from another balance can occur) Text
    status Current Batch Group Status Text
    groupType Whether this batch was submitted over the "API" or as a "FILE" Text
    transferIds The IDs of all transfers in the group. Array

    Error responses

    See errors page for a general description of API error responses. For all requests “401 Unauthorized” and 5xx series errors are possible.

    HTTP status Reason
    400 Bad Request Missing / invalid request arguments, or unsupported payment type
    422 Unprocessable Entity There is insufficient funds in the multi-currency account

    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"
      }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    1. 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>,
              "language":"PT"
            }'
    1. Example Response: Create User (Success (200) user created successfully)
          {
            "id": 12345,
            "name": null,
            "email": "new.user@domain.com",
            "active": true,
            "details": null
          }
    1. 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"
                ]
              }
            ]
          }
    
    
    
    
    
    
    
    
    1. 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' 
    1. 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"
        }
    1. Example Response: Get User Tokens (Failure: 401 - User reclaimed the account or invalid registration code used)
        {
          "error": "invalid_grant",
          "error_description": "Invalid user credentials."
        }

    This feature is related to Bank Integrations product. It enables onboarding new users to Wise via backend API calls only. To get authorization from Transferwise existing 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 the username/password. The body of the request must be sent as 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. Text
    token_type "bearer" Text
    expires_in Expiry time in seconds Integer
    scope "transfers" Text

    2) Create User

    Wise 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 a warning that "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
    language (Optional) User default language for UI and email communication.
    Allowed values EN, US, PT, ES, FR, DE, IT, JA, RU, PL, HU, TR, RO, NL, HK. Default value EN.
    Text, 2 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 Wise 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 the username/password. The body of the request must be sent as x-www-form-urlencoded.

    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. Text
    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. Text
    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",
                "firstNameInKana": null,
                "lastNameInKana": null
               }
            }'

    Example Response (Personal):

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

    Create personal user profile. One person cannot have multiple active duplicate user profiles, creating multiple profiles with the same details will fail.

    Request

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

    Field Description Format Validation rules (java regex)
    type "personal" Text Must be "personal".
    details.firstName First name (including middle names) Text (max 30 chars) Must not contain: %#^@{}"!~<>\. ((^[^%#^@{}"!~<>\\]+$))
    details.lastName Last name Text (max 30 chars) Must not contain: %#^@{}"!~<>\. ((^[^%#^@{}"!~<>\\]+$))
    details.dateOfBirth Date of birth YYYY-MM-DD Must be YYYY-MM-DD format.
    details.phoneNumber Phone number Text Must be a valid phone number, validated through Google's phone number library.
    details.firstNameInKana First name in Katakana (required for from JPY personal transfers) Text (Katakana) Must be in katakana with double width space or standard spaces only. ([\p{InKatakana} \u3000]+)
    details.lastNameInKana Last name in Katakana (required for from JPY personal transfers) Text (Katakana) Must be in katakana with double width space or standard spaces only. ([\p{InKatakana} \u3000]+)

    If a customer you are creating a profile for has first or last names that exceed 30 characters (e.g. they have many middle names) then you should truncate the names at length 30 characters and submit that value.

    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 (Deprecated) Person occupation Text
    details.occupations Array of occupations, currently one FREE_FORM occupation is supported, required as described above. Array (can be null or empty)
    details.occupations[n].code User occupation, any value permitted. Text
    details.occupations[n].format Occupation type - always FREE_FORM Text
    details.primaryAddress Address object id Integer
    details.firstNameInKana First name in Katakana (required for from JPY personal transfers) Text (Katakana)
    details.lastNameInKana Last name in Katakana (required for from JPY personal transfers) Text (Katakana)

    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": 123456, //ID of placeholder
        "businessCategory": "CONSULTING_IT_BUSINESS_SERVICES",
        "businessSubCategory": "DESIGN"
       }
    }

    Create business user profile. You must always create a personal profile first, business profiles cannot be created without personal profile.

    Request (Business)

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

    Field Description Format Validation Rules (java regex)
    type "business" Text Always "business"
    details.name Business name Text Must not contain: %#^@{}"!~<>\. ((^[^%#^@{}"!~<>\\]+$))
    details.registrationNumber Business registration number Text 1 to 30 characters.
    details.acn Australian Company Number (only for Australian businesses) Text Must be valid ACN.
    details.abn Australian Business Number (only for Australian businesses) Text Must be valid ABN.
    details.arbn Australian Registered Body Number (only for Australian businesses) Text Must be valid ARBN.
    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 Must be one of the enum values.
    details.companyRole Role of person. Allowed Values:
    • OWNER
    • DIRECTOR
    • OTHER
    Text Must be one of the enum values.
    details.descriptionOfBusiness Sector / filed of activity (DEPRECATED) Text Deprecated, use businessCategory and set this as null.
    details.webpage (conditional) Business webpage. Required if companyType is OTHER Text Valid URL. (^(?i)\\b(https?://)?((?=[a-z0-9-]{1,63}\\.)[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,63}\\b(/.*)*$)
    details.businessCategory Type of business, see below for permitted values Text One of the below Business Category values.
    details.businessSubCategory Specific sub category of the business type, see below for permitted values Text A valid subcategory of the selected businessCategory.

    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 us to discuss alternate solutions.

    The categories and their sub-categories are as follows:

    • CHARITY_NON_PROFIT
      • CHARITY_ALL_ACTIVITIES
    • CONSULTING_IT_BUSINESS_SERVICES
      • ADVERTISING_AND_MARKETING
      • ARCHITECTURE
      • COMPANY_ESTABLISHMENT_FORMATION_SERVICES
      • DESIGN
      • FINANCIAL_CONSULTING_ACCOUNTING_TAXATION_AUDITING
      • IT_DEVELOPMENT
      • IT_HOSTING_SERVICES
      • IT_CONSULTING_AND_SERVICES
      • LEGAL_SERVICES
      • MANAGEMENT_CONSULTING
      • SCIENTIFIC_AND_TECHNICAL_CONSULTING
      • SOFTWARE_AS_A_SERVICE
      • TRANSLATION_AND_LANGUAGE_SERVICES
      • CONSULTING_OTHER
      • SERVICES_OTHER
      • FREELANCE_PLATFORMS
      • RECRUITMENT_SERVICES
      • MAINTENANCE_SERVICES
      • FREELANCE_PLATFORMS
    • DESIGN_MARKETING_COMMUNICATIONS
      • ADVERTISING_AND_MARKETING
      • ARCHITECTURE
      • AUDIO_AND_VIDEO
      • DESIGN
      • PHOTOGRAPHY
      • PRINT_AND_ONLINE_MEDIA
      • TELECOMMUNICATIONS_SERVICES
      • TRANSLATION_AND_LANGUAGE_SERVICES
    • MEDIA_COMMUNICATION_ENTERTAINMENT
      • ADULT_CONTENT
      • AUDIO_AND_VIDEO
      • FINE_ARTS
      • ARTS_OTHER
      • EVENTS_AND_ENTERTAINMENT
      • GAMBLING_BETTING_AND_ONLINE_GAMING
      • NEWSPAPERS_MAGAZINES_AND_BOOKS
      • PERFORMING_ARTS
      • PHOTOGRAPHY
      • TELECOMMUNICATIONS_SERVICES
      • VIDEO_GAMING
    • EDUCATION_LEARNING
      • SCHOOLS_AND_UNIVERSITIES,
      • TEACHING_AND_TUTORING
      • ONLINE_LEARNING
    • FINANCIAL_SERVICES_PRODUCTS_HOLDING_COMPANIES
      • CROWDFUNDING
      • CRYPTOCURRENCY_FINANCIAL_SERVICES
      • FINANCIAL_CONSULTING_ACCOUNTING_TAXATION_AUDITING
      • HOLDING_COMPANIES
      • INSURANCE
      • INVESTMENTS
      • MONEY_SERVICE_BUSINESSES
      • FINANCIAL_SERVICES_OTHER
    • FOOD_BEVERAGES_TOBACCO
      • ALCOHOL
      • FOOD_MANUFACTURING_RETAIL
      • RESTAURANTS_AND_CATERING
      • SOFT_DRINKS
      • TOBACCO
      • VITAMINS_AND_DIETARY_SUPPLEMENTS
    • HEALTH_PHARMACEUTICALS_PERSONAL_CARE
      • HEALTH_AND_BEAUTY_PRODUCTS_AND_SERVICES,
      • DENTAL_SERVICES,
      • DOCTORS_AND_MEDICAL_SERVICES,
      • ELDERLY_OR_OTHER_CARE_HOME,
      • FITNESS_SPORTS_SERVICES,
      • MEDICAL_EQUIPMENT,
      • NURSING_AND_OTHER_CARE_SERVICES,
      • PHARMACEUTICALS,
      • PHARMACY,
      • VITAMINS_AND_DIETARY_SUPPLEMENTS
    • PUBLIC_GOVERNMENT_SERVICES
      • PUBLIC_ALL_SERVICES
      • MAINTENANCE_SERVICES
      • GOVERNMENT_SERVICES
      • TELECOMMUNICATIONS_SERVICES
      • UTILITY_SERVICES
    • REAL_ESTATE_CONSTRUCTION
      • ARCHITECTURE
      • CONSTRUCTION
      • REAL_ESTATE_DEVELOPMENT
      • REAL_ESTATE_SALE_PURCHASE_AND_MANAGEMENT
    • RETAIL_WHOLESALE_MANUFACTURING
      • AGRICULTURE_SEEDS_PLANTS
      • FINE_ARTS
      • ARTS_OTHER
      • AUTOMOTIVE_SALES_SPARE_PARTS_TRADE
      • AUTOMOTIVE_MANUFACTURING
      • CHEMICALS
      • CLOTHING
      • ELECTRICAL_PRODUCTS
      • FIREARMS_WEAPONS_AND_MILITARY_GOODS_SERVICES
      • HOME_ACCESSORIES_FURNITURE
      • FINE_JEWELLERY_WATCHES
      • FASHION_JEWELLERY
      • HEALTH_AND_BEAUTY_PRODUCTS_AND_SERVICES
      • LEGAL_HIGHS_AND_RELATED_ACCESSORIES
      • MACHINERY
      • PETS
      • PRECIOUS_STONES_DIAMONDS_AND_METALS
      • SPORTING_EQUIPMENT
      • MANUFACTURING_OTHER
      • RETAIL_WHOLESALE_MARKETPLACE_AUCTION
      • RETAIL_WHOLESALE_OTHER
      • TOYS_AND_GAMES
    • TRAVEL_TRANSPORT_TOUR_AGENCIES
      • ACCOMMODATION_HOTELS
      • PASSENGER_TRANSPORT
      • FREIGHT_TRANSPORT
      • RIDESHARING_TRANSPORT_SHARING_SERVICES
      • TRANSPORT
      • TRAVEL_AGENCIES
      • TOUR_OPERATORS
      • TRAVEL_OR_TOUR_ACTIVITIES_OTHER
    • OTHER
      • OTHER_NOT_LISTED_ABOVE

    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 Number (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 Specific 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 '{
              "id": <your personal profile id>
              "type": "personal",
              "details": {
                "firstName": "Oliver",
                "lastName": "Wilson",
                "dateOfBirth": "1977-07-01",
                "phoneNumber": "+3725064992",
                "firstNameInKana": null,
                "lastNameInKana": null
               }
            }'

    Example Response:

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

    Update user profile information.

    If user profile has been verified then there are restrictions on what information is allowed to change, where permitted, use the update window functionality to submit updated data.

    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,
        "firstNameInKana": null,
        "lastNameInKana": 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": "",
            "occupations": null,
            "primaryAddress": null,
            "firstNameInKana": null,
            "lastNameInKana": 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 (conditional) Document type. Allowed Values:
    • DRIVERS_LICENCE
    • IDENTITY_CARD
    • GREEN_CARD
    • MY_NUMBER
    • PASSPORT
    • SSN
    • EMPLOYER
    • OTHER
    Text
    uniqueIdentifier (required) 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. YYYY-MM-DD
    nationality 2 characters ISO country code. Text
    employerName The name of the employer. Type must be EMPLOYER. Text
    employerCity The city of the employer. Type must be EMPLOYER. Text
    employerCountry 2 characters ISO country code. Type must be EMPLOYER. Text
    birthCity The city of birth of the customer. Type must be OTHER Text
    birthCountry 2 characters ISO country code. Type must be OTHER Text

    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

    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

    When calling these endpoints if you include an Accept-Language header with a supported language code as the value then strings will be returned in the requested language. The languages supported by Wise 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.

    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:

    • Has a valid domain name (IP addresses are disallowed)
    • Listens to HTTPS requests on port 443
    • Has a valid HTTPS certificate signed by a trusted Certificate Authority - CA (self-signed or expired certificates are not accepted)
    • Does not include any query arguments in the URL

    https://webhooks.example.com/balance-change is a valid URL; http://webhooks.example.com:8080/hook.php?type=balance 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 the username/password. The body of the request must be sent as 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. Text
    token_type "bearer" Text
    expires_in Expiry time in seconds Integer
    scope Text

    Create

    Example Request:

    curl -X POST "https://api.sandbox.transferwise.tech/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.sandbox.transferwise.tech/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 Choose from a list of available events 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 Choose from a list of available events 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.sandbox.transferwise.tech/v3/applications/{clientKey}/subscriptions/{id}" \
      -H "Authorization: Bearer <your client level token>"

    Example Response:

    Request

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

    Get by ID

    Retrieves a subscription by its identifier.

    Example Request:

    curl -X GET "https://api.sandbox.transferwise.tech/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": "balances#credit", 
        "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:00Z"
    }

    Request

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

    Test notifications

    Test notifications can be generated for existing application subscriptions using the API.

    Test notifications will have the correct structure for their source subscription's event type and version, and will contain "dummy" data. These data include random UUIDs, entity IDs of zero, current dates and times, and hard-coded status codes.

    Test notifications are delivered with the usual notification HTTP request headers, including a unique delivery ID for the notification, and a "test notification" flag set to true. You can check for the presence of this test flag to determine that an incoming notification is a test notification which should not be processed as real data. See the section Event HTTP requests for more information on request headers.

    When test notifications are created with the API, they are queued for sending in the same way as non-test notifications. This means that there may be some delay in notification delivery, and delivery failures will result in attempts to redeliver the notification later. The API returns the delivery IDs of the notifications that have been successfully queued for sending, which can be correlated with the delivery ID header values for notifications you later receive.

    Example Request:

    curl -X POST "https://api.sandbox.transferwise.tech/v3/applications/{clientKey}/subscriptions/{subscriptionId}/test-notifications" \
      -H "Authorization: Bearer <your client level token>"

    Example Response:

    [
      {
        "delivery_id": "4a6b9810-4279-4de5-8d8d-1a6cf3b92a75",
        "created_at": "2019-03-28T11:22:33Z"
      }
    ]

    Example Test Notification:

    x-signature: bnho0q9JhjR6IPJIOZqWVP...
    x-delivery-id: 4a6b9810-4279-4de5-8d8d-1a6cf3b92a75
    x-test-notification: true
    
    {
      "data": {
        "resource": {
          "id": 0,
          "profile_id": 0,
          "account_id": 0,
          "type": "transfer"
        },
        "current_state": "processing",
        "previous_state": "incoming_payment_waiting",
        "occurred_at": "2019-03-28T11:22:33Z"
      },
      "subscription_id": "39f241b7-293d-439e-beb3-4bf947bd4ff8",
      "event_type": "transfers#state-change",
      "schema_version": "2.0.0",
      "sent_at": "2019-03-28T11:22:33Z"
    }
    

    Request

    POST https://api.sandbox.transferwise.tech/v3/applications/{clientKey}/subscriptions/{subscriptionId}/test-notifications

    Response

    List of test notifications that were scheduled for delivery.

    Field Description Format
    delivery_id UUID that uniquely identifies the notification Text
    created_at Time the notification was created Text

    List

    List all your subscriptions.

    Example Request:

    curl -X GET "https://api.sandbox.transferwise.tech/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.sandbox.transferwise.tech/v3/applications/{clientKey}/subscriptions

    Profile Webhooks

    Profile 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 under a specific profile.

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

    • Has a valid domain name (IPs are disallowed)
    • Listens to HTTPS requests on port 443
    • Has a valid HTTPS certificate signed by a trusted Certificate Authority - CA (self-signed or expired certificates are not accepted)
    • Does not include any query arguments in the URL

    https://webhooks.example.com/balance-change is a valid URL; http://webhooks.example.com:8080/hook.php?type=balance 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.

    If you will be dealing with multiple profiles in your integration, check out application webhooks. You will have to subscribe only once and you will receive updates concerning all resources that were created in your application.

    There are two ways you can manage profile webhooks:

    • via API (read more below)
    • via user interface (go to your settings page)

    Create

    Create a profile subscription.

    URL validation

    Our system will validate the requested delivery URL before creating a subscription.

    A test notification will be sent to the URL and if a 2xx-series HTTP response is not received then the creation request will be rejected with error code INVALID_CALLBACK_URL.

    Your notification endpoint must be ready to respond to the test notification. Test notifications can be distinguished by the presence of an HTTP request header. See the section Event HTTP requests for more information on request headers.

    Example Request:

    curl -X POST "https://api.transferwise.com/v3/profiles/{profileId}/subscriptions" \
      -H "Authorization: Bearer <your user 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": "profile", 
            "id": "<profile ID>"
        },
        "created_by": {
            "type": "user",
            "id": "<your user ID>"
        },
        "created_at": "2008-09-15T15:53:00Z"
    }

    Request

    POST https://api.transferwise.com/v3/profiles/{profileId}/subscriptions

    profileId - ID of the profile you are subscribing to.

    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 Choose from a list of available events Text
    delivery.version The event representation semantic 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, transfers#active-cases or balances#credit Text
    delivery.version The event representation semantic Text
    delivery.url Required. The URL where your server will be listening for events. Text
    scope.domain Scope of this subscription, always "profile" in this case Text
    scope.id Profile ID used to create this subscription Text
    created_by.type Creator type. Always user in this case Text
    created_by.id User id of the creator 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/profiles/{profileId}/subscriptions/{id}" \
      -H "Authorization: Bearer <your user token>"

    Example Response:

    Request

    DELETE https://api.transferwise.com/v3/profiles/{profileId}/subscriptions/{id}

    Get by ID

    Retrieves a subscription by its identifier.

    Example Request:

    curl -X GET "https://api.transferwise.com/v3/profiles/{profileId}/subscriptions/{id}" \
      -H "Authorization: Bearer <your user 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": "balances#credit", 
        "scope": {
            "domain": "profile", 
            "id": "<profile ID>"
        },
        "created_by": {
            "type": "user",
            "id": "<your user ID>"
        },
        "created_at": "2008-09-15T15:53:00Z"
    }

    Request

    GET https://api.transferwise.com/v3/profiles/{profileId}/subscriptions/{id}

    List

    List all your subscriptions

    Example Request:

    curl -X GET "https://api.transferwise.com/v3/profiles/{profileId}/subscriptions" \
      -H "Authorization: Bearer <your user 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": "user",
          "id": "<your user ID>"
        },
        "scope": {
          "domain": "profile",
          "id": "<profile ID>"
        }
      },
      {
        "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": "user",
          "id": "<your user ID>"
        },
        "scope": {
          "domain": "profile",
          "id": "<profile ID>"
        }
      }
    ]

    Request

    GET https://api.transferwise.com/v3/profiles/{profileId}/subscriptions

    Webhook events

    Webhook events are messages that describe certain business events that occur within Wise's system. For example, an event may describe a change in the status of a transfer you have made.

    Events that are related to your Wise resources can be sent to your server as HTTP POST requests. You can start receiving events by creating webhook subscriptions using the Wise Platform API or website interface.

    Subscriptions specify what type of event should be sent, and what server location the event should be sent to.

    Events will not contain any personally identifiable information.

    Webhook handlers

    To receive events, you must set up a publicly accessible HTTPS endpoint and create a subscription that uses this endpoint. Our system will send HTTP POST requests to this endpoint with events encoded using JSON.

    Your system must respond with a 2xx-series HTTP status code within 5 seconds of receiving a request to acknowledge successful delivery of a webhook notification. If this "success" response is not received by us within this time period, 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.

    A recommended strategy for handling notifications is to do some basic validation and then store the notification for processing by a separate server process. This will avoid our delivery system from considering delivery attempts to have failed if your handler does not respond in time due to a long handling process. Basic validation could include signature verification (see below).

    Event HTTP requests

    Event HTTP request bodies have a type-specific structure. Events using version 2 of our type schema will contain a common base structure with additional event-specific details. Each event type is described in detail later in this section.

    Event HTTP requests also contain the following custom headers:

    Signature header X-Signature-SHA256

    Wise's public webhook signing key for the production environment:

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

    Wise's public webhook signing key for the sandbox environment:

    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwpb91cEYuyJNQepZAVfP
    ZIlPZfNUefH+n6w9SW3fykqKu938cR7WadQv87oF2VuT+fDt7kqeRziTmPSUhqPU
    ys/V2Q1rlfJuXbE+Gga37t7zwd0egQ+KyOEHQOpcTwKmtZ81ieGHynAQzsn1We3j
    wt760MsCPJ7GMT141ByQM+yW1Bx+4SG3IGjXWyqOWrcXsxAvIXkpUD/jK/L958Cg
    nZEgz0BSEh0QxYLITnW1lLokSx/dTianWPFEhMC9BgijempgNXHNfcVirg1lPSyg
    z7KqoKUN0oHqWLr2U1A+7kqrl6O2nx3CKs1bj1hToT1+p4kcMoHXA7kA+VBLUpEs
    VwIDAQAB
    

    How to verify SHA256 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("SHA256WithRSA");
      sign.initVerify(publicKey);
      sign.update(payload.getBytes());
      
      byte[] signatureBytes = Base64.getDecoder().decode(signature);
      
      return sign.verify(signatureBytes);
    }

    Each outgoing webhook request is signed. You should verify that any request you handle was sent by Wise and has not been forged or tampered with. You should not process any requests with signatures that fail verification.

    Signatures are generated using an RSA key and SHA256 digest of the message body. They are transmitted using the X-Signature-SHA256 request header and are Base64 encoded.

    We have provided some sample Java code that uses the SHA256WithRSA signing algorithm to verify a message.

    Delivery ID header X-Delivery-Id

    Each outgoing notification is assigned a unique delivery UUID.

    Test notification header X-Test-Notification

    This header is present with the value true if the notification is a test message.

    Test messages can be sent to verify callback URLs when subscriptions are being set up.

    Event payload

    All event notification payloads have the same high-level structure. Top-level properties are common to all events. The data property is an object that can contain various properties. The exact properties that the data object contains depends on the event type and schema version of the event.

    Basic event payload:

    {
      "data": {},
      "subscription_id": "01234567-89ab-cdef-0123-456789abcdef",
      "event_type": "event#type",
      "schema_version": "2.0.0",
      "sent_at": "2020-01-01T12:34:56Z"
    }

    Common properties

    Field Description Format
    data Event type- and schema version-specific details Object
    subscription_id ID of the webhook subscription that triggered the event notification Text
    event_type Event type (what event happened in our system) String
    schema_version Schema version (what notification structure is being used to model the event) String
    sent_at When the event notification was sent from our system Datetime

    Event types

    The follow event types are available. Please note that some event types are restricted to certain types of webhook subscription.

    Event type Profile subscriptions Application subscriptions
    transfers#state-change supported supported
    transfers#active-cases supported not supported
    balances#credit supported not supported
    profiles#verification-state-change not supported supported

    Transfer status change event

    Event type: transfers#state-change

    This event will be triggered every time a transfer's status is updated. Each event contains a timestamp. As we do not guarantee the order of events, please use data.occurred_at to reconcile the order.

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

    Example v2.0.0 transfers#state-change event:

    {
      "data": {
        "resource": {
          "type": "transfer",
          "id": 111,
          "profile_id": 222,
          "account_id": 333
        },
        "current_state": "processing",
        "previous_state": "incoming_payment_waiting",
        "occurred_at": "2020-01-01T12:34:56Z"
      },
      "subscription_id": "01234567-89ab-cdef-0123-456789abcdef",
      "event_type": "transfers#state-change",
      "schema_version": "2.0.0",
      "sent_at": "2020-01-01T12:34:56Z"
    }

    Schema version 2.0.0 (latest)

    Field Description Format
    data.resource.type Transfer resource type (always transfer) String
    data.resource.id ID of the transfer Integer
    data.resource.profile_id ID of the profile that owns the transfer Integer
    data.resource.account_id ID of transfer's recipient account Integer
    data.current_state Current transfer state (see transfer statuses) String
    data.previous_state Previous transfer state (see transfer statuses) String
    data.occurred_at When the state change occurred Datetime

    Transfer active cases event

    Event type: transfers#active-cases

    This event will be triggered every time a transfer's list of active cases is updated. Active cases indicate potential problems with transfer processing.

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

    Example v2.0.0 transfers#active-cases event:

    {
      "data": {
        "resource": {
          "type": "transfer",
          "id": 111,
          "profile_id": 222,
          "account_id": 333
        },
        "active_cases": ["deposit_amount_less_invoice"]
      },
      "subscription_id": "01234567-89ab-cdef-0123-456789abcdef",
      "event_type": "transfers#active-cases",
      "schema_version": "2.0.0",
      "sent_at": "2020-01-01T12:34:56Z"
    }

    Schema version 2.0.0 (latest)

    Field Description Format
    data.resource.type Transfer resource type (always transfer) String
    data.resource.id ID of the transfer Integer
    data.resource.profile_id ID of the profile that owns the transfer Integer
    data.resource.account_id ID of transfer's recipient account Integer
    data.active_cases Ongoing issues related to the transfer List of strings

    Balance credit event

    Event type: balances#credit

    This event will be triggered every time a balance account is credited.

    If you would like to subscribe to balance credit events, please use balances#credit when creating your subscription.

    Please note: This event is not currently delivered to application subscriptions.

    Example v2.0.0 balances#credit event:

    {
      "data": {
        "resource": {
          "type": "balance-account",
          "id": 111,
          "profile_id": 222
        },
        "transaction_type": "credit",
        "amount": 1.23,
        "currency": "EUR",
        "post_transaction_balance_amount": 2.34,
        "occurred_at": "2020-01-01T12:34:56Z"
      },
      "subscription_id": "01234567-89ab-cdef-0123-456789abcdef",
      "event_type": "balances#credit",
      "schema_version": "2.0.0",
      "sent_at": "2020-01-01T12:34:56Z"
    }

    Schema version 2.0.0 (latest)

    Field Description Format
    data.resource.type Balance account resource type (always balance-account) String
    data.resource.id ID of the balance account Integer
    data.resource.profile_id ID of the profile that owns the balance account Integer
    data.transaction_type Always credit String
    data.amount Deposited amount Decimal
    data.currency Currency code String
    data.post_transaction_balance_amount Balance amount after the credit was applied Decimal
    data.occurred_at When the balance credit occurred Datetime

    Verification state change event

    Event type: profiles#verification-state-change

    This event will be triggered when the verification state of a connected profile changes.

    A profile's verification state can be verified or not_verified. If the state is verified, then the user is ready to make payments using Wise. If the state is not_verified, then we advise not to initiate any transfers with the user's access token as the payments will not be processed until the verification is completed.

    There is a more in-depth discussion of verification state in our Connected Apps Integration Guide.

    Please note: This event is currently delivered only to application subscriptions.

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

    Example v2.0.0 profiles#verification-state-change event:

    {
      "data": {
        "resource": {
          "type": "profile",
          "id": 111
        },
        "current_state": "verified",
        "occurred_at": "2020-01-01T12:34:56Z"
      },
      "subscription_id": "01234567-89ab-cdef-0123-456789abcdef",
      "event_type": "profiles#verification-state-change",
      "schema_version": "2.0.0",
      "sent_at": "2020-01-01T12:34:56Z"
    }

    Schema version 2.0.0 (latest)

    Field Description Format
    data.resource.type Profile resource type (always profile) String
    data.resource.id ID of the profile Integer
    data.current_state Current verification state of the profile (see discussion above) String
    data.occurred_at When the verification state change occurred Datetime

    Webhooks version 1 (deprecated)

    You can use profile webhooks or application webhooks instead.

    List

    Example Request:

    curl -X GET https://api.sandbox.transferwise.tech/v1/subscriptions?channelId=webhook \
      -H "Authorization: Bearer <your api token>"

    Example Response:

    [
      {
        "id": "abcde123-abcd-abcd-abcd-abcde1234567",
        "name": "Webhook Subscription #1",
        "channel_id": "WEBHOOK",
        "user_id": "TW::<your user ID>",
        "status": "ENABLED",
        "created_on": "2019-03-10T09:32:15.663Z",
        "url": "<URL of your server>",
        "profile_id": <ID of the profile you want to receive notifications from>,
        "enabled_notifications": [
          "balance"
        ]
      },
      {
        "id": "abcde123-abcd-abcd-abcd-abcde1234568",
        "name": "Webhook Subscription #2",
        "channel_id": "WEBHOOK",
        "user_id": "TW::<your user ID>",
        "status": "ENABLED",
        "created_on": "2019-03-11T09:32:15.663Z",
        "url": "<URL of your server>",
        "profile_id": <ID of the profile you want to receive notifications from>,
        "enabled_notifications": [
          "transfers"
        ]
      }
    ]

    List all created webhook subscriptions.

    Response

    Field Description Format
    id Subscription ID Text
    name Custom name of your webhook String
    channel_id ID of the channel through which you're receiving notifications, always equal to WEBHOOK String
    user_id Your user ID Integer
    status Status of the subscription String
    created_on Timestamp when subscription was created Timestamp
    url URL of your server String
    profile_id ID of the profile you want to receive notifications from Integer
    enabled_notifications List of resources you would like to receive notifications about [String]

    Get by ID

    Example Request:

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

    Example Response:

    {
      "id": "abcde123-abcd-abcd-abcd-abcde1234567",
      "name": "Webhook Subscription #1",
      "channel_id": "WEBHOOK",
      "user_id": "TW::<your user ID>",
      "status": "ENABLED",
      "created_on": "2019-03-10T09:32:15.663Z",
      "url": "<URL of your server>",
      "profile_id": <ID of the profile you want to receive notifications from>,
      "enabled_notifications": [
        "balance",
        "transfers"
      ]
    }

    Get subscription information by ID.

    Response

    Field Description Format
    id Subscription ID Text
    name Custom name of your webhook String
    channel_id ID of the channel through which you're receiving notifications, always equal to WEBHOOK String
    user_id Your user ID Integer
    status Status of the subscription String
    created_on Timestamp when subscription was created Date
    url URL of your server String
    profile_id ID of the profile you want to receive notifications from Integer
    enabled_notifications List of resources you would like to receive notifications about [String]

    Delete

    Example Request:

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

    Example Response:

    {
    }

    Delete a subscription.

    Events

    Events are messages that will be sent to your server as HTTP POST requests. They will not contain any personally identifiable information.

    To acknowledge that you have successfully processed an event, make sure your server answers with a 2xx-series HTTP status code within 5 seconds. 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

    Wise 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 Wise (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.

    Test event

    Example Request:

    curl -X POST https://api.sandbox.transferwise.tech/v1/webhooks/ping \
      -H "Authorization: Bearer <your api token>" \
      -H "Content-Type: application/json" \
      -d '{
           "callback_url": "<URL of your server>"
          }'

    Example Response:

    {
      "status": "SUCCESS",
      "code": 200,
      "elapsed": 228
    }

    You can trigger a test event to be delivered to your server to check the connection between systems.

    Request

    Field Description Format
    callback_url URL of your server String

    Response

    Field Description Format
    status Status of test notification delivery String
    code HTTP status code we have received from your server Integer
    elapsed Time taken to deliver notification, in ms Integer

    Transfer status change event

    Example event:

    {
      "subscriptionId": "abcde123-abcd-abcd-abcd-abcde1234567",
      "profileId": 123456,
      "resourceId": {transferId},
      "newState": "outgoing_payment_sent",
      "eventTime": 1481713589566
    }

    Event

    Event will be triggered every time transfer status is updated. Each event contains a timestamp. As we do not guarantee the order of events, please use that eventTime to reconcile the order.

    Field Description Format
    subscriptionId ID of subscription that triggers this notification String
    profileId ID of the profile that owns the resource Integer
    resourceId ID of the resource that got updated Integer
    newState New status of the resource, possible values are same as transfer statuses String
    eventTime Timestamp when update happened Timestamp

    Balance deposit event

    Example event:

    {
      "subscriptionId": "abcde123-abcd-abcd-abcd-abcde1234567",
      "profileId": 123456,
      "amount": 1000,
      "currency": "GBP",
      "eventType": "balance-deposit-received"
    }

    Event

    Event will be triggered every time balance is credited.

    Field Description Format
    subscriptionId ID of subscription that triggers this notification String
    profileId ID of the profile that owns the balance Integer
    amount Deposit amount Decimal
    currency Currency of the balance that got updated String
    eventType Type of update String

    Strong Customer Authentication

    Strong Customer Authentication (SCA) is a new European regulatory requirement as part of the second Payment Services Directive (PSD2) for authenticating online payments and make them more secure.

    There are some actions such as funding a transfer from your balance or viewing the statement that require SCA within the UK and EEA. SCA builds additional authentication by asking two of the following three elements: something the customer knows, something the customer has and something the customer is. If you don't integrate with it and make a request to an SCA protected endpoint, your request will be rejected.

    Following those regulations, we need our API to be more secured by ensuring multi-factor authentication from the end-user of the Wise account. Two mechanisms are in place depending on the product you are using:

    Personal Token

    When making a request to an SCA protected endpoint, a 403 Forbidden HTTP status code is returned together with a one-time token (OTT) value which needs to be signed and the resulting signature included in the retry of the original request.

    Below is a sequence diagram showing this flow.

    Example SCA flow

    We use a digital signature scheme based on public-key cryptography. It involves creating a signature using a private key on the client side and verifying the signature authenticity on the server side using the corresponding public key the client has uploaded.

    To call the endpoints requiring additional authentication:

    • Create a key pair consisting of a public and a private key
    • Upload the public key to Wise
    • Set up response handling to retry with the signed OTT

    Creating the key pair

    Keys can be generated with the OpenSSL toolkit:

    $ openssl genrsa -out private.pem 2048
    $ openssl rsa -pubout -in private.pem -out public.pem

    The following requirements apply:

    • The cryptographic algorithm has to be RSA
    • The key length has to be at least 2048 bits
    • The public key should be stored in PEM file format using a .pem file extension

    Managing uploaded public keys

    The public keys management page can be accessed via the "Manage public keys" button under the API tokens section of your Wise account settings.

    You will be prompted to perform 2FA when uploading new public keys.

    The maximum number of public keys you can store is limited to 5.

    Signing the data

    We will only accept the signatures created with SHA256 with RSA (SHA256 hash of the data is signed with RSA) algorithm. There are different ways of creating the required digital signature, for example:

    The shell one-liner to sign a string, encode it with Base64 and print to standard output:

    $ printf '<string to sign>' | openssl sha256 -sign <path to private key.pem> | base64 -w 0
    • OpenSSL

      The CLI toolkit command is openssl sha256 -sign private.pem data.bin (consult the openssl man pages for additional info if required). Note that the signature returned by OpenSSL (to standard output in the example above) is in a binary format and to send it over HTTP it should be encoded to Base64 (RFC 4648)).

      There is also an extensive C API available.

    • Our reference implementation Java library

    • Reference implementations in Python & Go

    Detailed workflow

    Here is a step-by-step workflow with example commands (which may vary slightly depending on the exact versions of utilities used).

    $ curl -i -X POST 'https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/transfers/{transferId}/payments' \
           -H 'Content-Type: application/json' \
           -H 'Authorization: Bearer <your api token>' \
           -d '{"type": "BALANCE"}'
    1. Client makes a request which requires strong authentication.
    HTTP/1.1 403 Forbidden
    Date: Fri, 03 Jan 2020 12:34:56 GMT
    Content-Type: application/json;charset=UTF-8
    x-2fa-approval-result: REJECTED
    x-2fa-approval: be2f6579-9426-480b-9cb7-d8f1116cc8b9
    ...
    {
        "timestamp": "2020-01-03T12:34:56.789+0000",
        "status": 403,
        "error": "Forbidden",
        "message": "You are forbidden to send this request",
        "path": "/v3/profiles/{profileId}/transfers/{transferId}/payments"
    }
    1. The request is declined with HTTP status 403 / Forbidden with the following response headers
      • X-2FA-Approval-Result: REJECTED
      • X-2FA-Approval containing the one-time token (OTT) value which is what needs to be signed
    $ printf 'be2f6579-9426-480b-9cb7-d8f1116cc8b9' | openssl sha256 -sign private.pem | base64 -w 0
    1ZCN1MIDdmonOJvNQvsCxRHMXihsqZ/xNvybhb3oYNQgRkyj2P0hCVVaWUbr313LicFGwRTW8kcxTwvpXQdeurGtcN2zGoweVTopI06dmJ8vQMfTkrqjMZG3UUX0EcU+tJaDlBemvS7gv2aNGyHDMiRPZOZRPA6TH0LPJvLdVRMsEbXrbj8HqEopczmf1jChRxftmg2XoeQUMhhlOiSjSbJmlyAIegioI40/BTii+Q7f/HWZqk6N2vmHWPomwHQMz8Hy6frLYJb5tchjg/i+RRvZjEVbUH53QfG8Tbmx4JM/wN1LYeR8rebSdGEpLOd8QRcjuDur54qHNWXvKRM8aQ==

    with private.pem private key:

    -----BEGIN RSA PRIVATE KEY-----
    MIIEpAIBAAKCAQEA3qfjPkhbTPKJQqLm+KfHP14wJ2U318Rh/4TV8xLi605xFW7r
    ApzXzLLxBb7zSkBc9wFIEH7wU7/BaFivg440R7ktYR07/QXZi+i0grKbfhEBW1nU
    jkI2eZxT3vE4VIK7Yt2jr84JiCYmjL2b/w1DatXZM9Xoa3j9YHda5cKLOfCCIeTs
    I3beYI9UmSnidYaXpX7q4gfHME+A/1F/19L8jFvX+c7MXapdCdY/NUHXBCJFfBzg
    OBlXbPKhdjtEnx+Hg5Sq/Frsld6dKwF1CDMO96YoeXBdi58JkLL/CLyy1i7UcXTb
    SRy0Gbd3NWSAamWdpJDDg51UR6yRJdXjtnhpdQIDAQABAoIBAGs3/4bzgvvH428y
    UPU2ng0WxyuBY2XEzMgl6H04AAv95xjCI+tLKeQJ22S/8ho0alALzu8aoZJCydj8
    s/Au32AWfRLB6CxMz9i+w4YYiiYn/DZISMIEgoUHUaAPGugfWCsgvf0fw5lLfc7S
    U7d7ZJaiyghbHqP6TFFSyHPRvge0so+8eRvPMxIGdfJR3gagJqKB5JbTGAnQ5Kn2
    eb5flDOobmCfpLDfIYH9u94Yj671xymtNYXwWxic4gA+aqWJKaqkI8JL7bFdjvjn
    Jer5RHeXmY9UZtDhSrZWSEKniw3m02QPpgqhhhPr8xToNA/7G1/P9994fuDKKnRk
    edn3FEECgYEA8iTPuaNGswyx/3zCkOPHHu82CSoWRZQapegN0YoXKsCyEWcHgQJV
    jZlF39OK14+y4PWWPJ3AlkhrchAJbUbgpw0P+G1uiRmXVpqcaEI4xIFd8oSOG+Vr
    s06YZYUrb7C73mi8x3sXdOpmehMYdnSbuxrRXyk0MwpLO2PkC0wXzEUCgYEA62WY
    RuZMAHR4PEZA+sDBG6XzjZGw1QQvF7H6u+JOfgPbRgZ+NnLQ/ZpYiDvrJGqAp1B1
    NIj69zVBN0p7PuRg2v9I4tHlmWC4eyYnVCf3dM6Fhsyb7RC3MHXVNOErxRoHVNqL
    4iywSUnboJyvdyKc7S5wQ5gdM14HogD/i1FHs3ECgYBMuMcsfYRgJOydE82eFN25
    ene3jaNC5ntPB+ig9M0EWcvR4cAp6zBqTh8qnR9Hz5sQ1h+FE0K7GzUYDea+vg9e
    PrBJuXqla/tckF5wVlMgSBEZT1CrnBR02rlEqV4q5GeSP8NYvTKgc8iGc1hz59yT
    +xpNuYN1jJRru+m8fp6ntQKBgQDd7Iglv5TDkQqR+MHmJbdpM4lsXIBUM3+aXUc/
    vtm1YDlnyVNQTerOTKdOuP609FuaYfY9sy63xVNYpzWOU40kqiyy+qP1eAQ0xgGq
    C4v2aYXlUh1m4K10WILLOcYkKqfiza+3ad5BGgqfX1jlfpJn4bIhZ9WPygR0LXC+
    jcCFYQKBgQCelF/LIocwZ1ZW/Cx2OqMi/lkI56nLeBl7jRNiBSNIs0deN0cw4sHp
    BN9459NojAKBKJK1pyqajzrHae66V+8/2Zz2/gmTK1dDjznyw6TZmV3QyHTFhUtY
    NI7wvIG9K8gFaoSiGD/OLlLRaGiAdejKBsBx2hK73M58YQsgqIpdIQ==
    -----END RSA PRIVATE KEY-----
    
    1. Client signs the OTT with the private key corresponding to a public key previously uploaded for signature verification.
    $ curl -i -X POST 'https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/transfers/{transferId}/payments' \
           -H 'Content-Type: application/json' \
           -H 'Authorization: Bearer <your api token>' \
           -H 'x-2fa-approval: be2f6579-9426-480b-9cb7-d8f1116cc8b9' \
           -H 'X-Signature: RjXBO5SpAuMGdgTyqPryOt8AyIKY0t5gHqj36MzR2UwH9SvSY1V1wKIQCqXRvLMLyWBGXDkLvv9JdAni+H87k3hsClRiyfpdzcg3uOP+d/jSagNDSjHixPh4/rWQh+eEhBRo4V+pPBH+r5APtIwFY/fvvdMbZ/QnnmcPHxi/t7uS7+qvRZCC17q47T0ZpSwEK9x+nG/wcJ4S4Yrk0E2yQlLz8F35C+E2gt/KGTt6Tf5z6GonM1H2gJWoHpxuOUomh09b/k3teLjIfEirWmnO2XuOe0oDCUH8i10dokzk+QrM4t/Yv/Rb18JvTeugDAKMydGo7KTgqKGCXZauicX0Ew==' \
           -d '{"type": "BALANCE"}'
    1. Client repeats the initial request with the OTT provided in the X-2FA-Approval request header and the signed OTT in the X-Signature request header.
    HTTP/1.1 200 OK
    Date: Fri, 03 Jan 2020 12:34:56 GMT
    Content-Type: application/json;charset=UTF-8
    x-2fa-approval-result: APPROVED
    
    {
      "type": "BALANCE",
      "status": "COMPLETED",
      "errorCode": null
    }
    1. Customer has authenticated and the action is completed. You will receive a response with x-2fa-approval-result status APPROVED in headers.

    Authorization code access tokens

    If you use the authorization code integration to integrate with our API, then this is the right place.

    When making a request to an SCA protected endpoint, a 403 Forbidden HTTP status code is returned together with a one-time token (OTT). Your customer will now expect to authenticate themselves by entering their Wise password as well as an OTP code. Our library was created by our team to make your integration easier.

    Below is a sequence diagram showing this flow.

    Example SCA flow

    Detailed workflow

    Here is a step-by-step workflow with example commands to process a payment (which may vary slightly depending on the exact versions of utilities used).

    import { create, Mode } from '@transferwise/approve-api-action-helpers';
    ...
    const request = create({ mode: Mode.PRODUCTION });
    const res = await request('/tw-fund-payment', { method: 'POST', data: { ... } });
    1. Your customer makes a request which requires strong authentication. The call is made using our SCA helper library from your frontend.
      $ curl -i -X POST 'https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/transfers/{transferId}/payments' \
             -H 'Content-Type: application/json' \
             -H 'Authorization: Bearer <your api token>' \
             -d '{"type": "BALANCE"}'
    1. Your server forwards the request to Wise Platform API.
    HTTP/1.1 403 Forbidden
    Date: Fri, 03 Jan 2020 12:34:56 GMT
    Content-Type: application/json;charset=UTF-8
    x-2fa-approval-result: REJECTED
    x-2fa-approval: be2f6579-9426-480b-9cb7-d8f1116cc8b9
    ...
    {
        "timestamp": "2020-01-03T12:34:56.789+0000",
        "status": 403,
        "error": "Forbidden",
        "message": "You are forbidden to send this request",
        "path": "/v3/profiles/{profileId}/transfers/{transferId}/payments"
    }
    1. The request is declined with HTTP status 403 / Forbidden with the following response headers
    • x-2fa-approval-result: REJECTED
    • x-2fa-approval containing the one-time token (OTT) value
    1. Your server reflects the response status and the header x-2fa-approval back to your frontend.

    2. Our frontend library now understands that SCA is required and asks the customer to pass challenges (such as password).

    3. When customer has completed challenges, our frontend library automatically triggers the initial call (1) again, but this time it includes the OTT (x-2fa-approval header) and sends it to your backend.

    $ curl -i -X POST 'https://api.sandbox.transferwise.tech/v3/profiles/{profileId}/transfers/{transferId}/payments' \
           -H 'Content-Type: application/json' \
           -H 'Authorization: Bearer <your api token>' \
           -H 'x-2fa-approval: be2f6579-9426-480b-9cb7-d8f1116cc8b9' \
           -d '{"type": "BALANCE"}'
    1. Your server repeats the initial request (2) with the addition of the one-time token.
    HTTP/1.1 200 OK
    Date: Fri, 03 Jan 2020 12:34:56 GMT
    Content-Type: application/json;charset=UTF-8
    x-2fa-approval-result: APPROVED
    
    {
      "type": "BALANCE",
      "status": "COMPLETED",
      "errorCode": null
    }
    1. Customer has authenticated and the action is completed. You will receive a response with x-2fa-approval-result status APPROVED in headers.

    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 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/0b63b0cb-2041-4bc4-b3fc-1e51a1454a1b/account-requirements"
    }

    Something went wrong in our side.

    FAQ

    User Onboarding

    Q: I need to update a redirect URL for my (Sandbox/Live) account. How can I do it?
    A: Our API tech support can help you with it. You can reach us via email api@wise.com or contact your account manager.
    Q: Why is it a good idea to show the Anonymous quote to the user before using the service or creating a new one?
    A: It is good for conversion, as it allows your users to check the cost and delivery estimate for each specific currency route prior to using the service.
    Q: Will our users receive any emails from Wise? Including transfer status updates, marketing emails and regular updates?
    A: All communications with the end-users will happen from your side. Though users, that already have a preexisting Wise account at the moment of linking will continue receiving email updates.
    Q: Is it required to Open/Close update window when creating a profile Address or is it only for updating address details?
    A: For creating an address it is not required. We generally recommend that you can create a single process (open window, send data, close window) in order to simplify things, but this is not necessary. For new profiles you can just call POST /v1/addresses without calling the open/close window APIs. For existing profiles, either created via API by your integration or directly with Wise, you need to call the open and close window endpoints.

    Transfer Flow

    Q: What is the purpose of POST /v1/transfer-requirements call? I have successfully created a transfer with no errors without using it.
    A: These requirements are needed for the recipient bank to successfully process your transfer according to the compliance requirements in the recipients country. Sometimes it is needed to specify transfer purpose or source of funds so you have to use transfer-requirements to check whether you need to specify these details. Without providing this info when it’s needed the transfer will be blocked from further processing.
    Q: The quote is valid only for 30 mins. Is it possible that the exchange rate and fee change after this time?
    A: The exchange rate will stay the same within guaranteed rate period of 2-72 hours. The price and delivery estimate can change depending on the recipient type the user chooses. Please see more information about this here

    Recipient

    Q: Do I have to provide a profileId when creating a recipient or quote? I have noticed that it works even without profileId.
    A: Yes, you have to explicitly specify a profileId to avoid any confusions on the client side. Without a specified profileId the personal profile will be assigned by default.
    Q: When creating KRW recipients I get an error about a missing email, but email is not returned as required with account-requirements.
    A: That is correct, you need to provide an email when creating recipients for some currencies. Set the request header Accept-Minor-Version to 1 to use this version to your account-requirements call and you will get the correct response. More info here
    Q: Do you have any test/example data that we can use for recipient creation? IBANS, SWIFTS, Account numbers etc for the currencies we will use for the launch?
    A: Currently we don’t have it in one list, but we return samples with account-requirements response. It is stored in an “example” field and you can also find a regex used for validation. Please contact our API Support api@wise.com in case if you have any questions.
    Q: Is it possible to edit a saved recipient's details over the API?
    A: It is not possible to change the details of the existing recipients, you would need to create a new one and delete the existing.
    Q: In order to get account-requirements I have to create a quote first and then based on this I can get account-requirements for this quote. Our flow starts with recipient creation. Do I still have to create a “placeholder” quote in order to get account-requirements?
    A: You can pass source, target currencies and amount as url parameters in the following format:

    GET https://api.sandbox.transferwise.tech/v1/account-requirements?source=EUR&target=USD&sourceAmount=1000

    This call doesn’t require an authentication header. Please note, this is not a recommended flow, as it doesn't take to account the amount and data requirements may be different when a customer actually comes to send a high amount transfer.

    Q: Do we have to provide an address when creating a recipient? How do I know whether or not the address is required?
    A: You have to use the account-requirements endpoint which returns the list of fields that are required to create a recipient. It also returns address requirements. A detailed guide on how to use account-requirements you can find here
    Q: When I try to create a SWIFT recipient I get an “unsupported country” error.
    A: Check the lists of countries where we can send USD, EUR, GBP via SWIFT network.
    Please note, you cannot send a local transfer via SWIFT (for example sending USD to US SWIFT code is not permitted).
    Q: If you need to add more than one account for the same recipient (ex: Like one Mexican account and one Brazilian account), is it correct to set these up as separate recipients?
    A: Yes, those will be separate recipients. They will share the same name but banking details and recipient IDs will be different.

    Webhooks

    Q: Will we get a webhook notification on each transfer status change event?
    A: Yes, you will get a webhook for each transfer status update. All the transfer statuses are documented here.
    Q: I've created a new application webhook subscription via API but it is not listed on the website UI on the Settings page.
    A: We list only profile webhooks on the Settings page. You can check your application webhooks with the endpoint documented here
    Q: We will have 1000+ customers, do l have to create 1000 endpoints to track transfer statuses? Do you have limitations for a number of webhook endpoints?
    A: You don’t have to create 1000 endpoints. You can use only one webhook callback url that will receive notifications regarding all of your managed accounts. The notification contains profileId so you will know which user owns this notification.
    Q: In the webhook notification I have seen 2 headers: “x-signature” and “x-signature-sha256”. Which one do we have to use?
    A: X-Signature-SHA256 header is recommended to use. It is based on SHA256WithRSA algo. The sha1-based header will remain; it is not technically deprecated, so won’t be removed for now.
    Q: When creating an Application webhook subscription, why do I get a 401 error response? I have obtained a client token but the subscription creation call fails.
    A: We have to add your clientId into the configuration file first. It is a quick process and after that you will be able to use Application webhooks.

    Sandbox

    Q: When I’m calling a Simulation endpoint it returns an error.
    A: After funding the transfer, you still have to manually simulate to “processing” status even though the transfer status returned with GET /v1/transfers/{{ID}} is “processing” already. Also it is not possible to simulate transfers to email recipients, as there is a special transfer status involved, which expects the recipient to provide its banking details.
    Q: I forgot my Sandbox password. How do I reset it?
    A: It is not possible to change the Sandbox password from the client side. Our API tech support can help you. Send and email to api@wise.com or contact your Account Manager. For reference, we don’t send any emails from Sandbox.

    Business

    Q: Do you have any certifications for data storage and management?
    A: Wise has ISO27001 certification. Wise products run on AWS cloud with their sites located in Germany and Ireland. Amazon holds their own ISO certification and offers the highest standards in information security. Wise may use outsourced customer support agents who would have access to some parts of the payment information. This arrangement is done in compliance with our data protection, information security and vendor management policies which are under GDPR regulations.
    Q: Are we licensed or regulated?
    A: Yes, we are licensed and/or regulated in many countries. A full list of our licensing status is available here.
    Q: Please confirm if an approved formal Data Protection Policy is in place and the role of DPO is properly assigned.
    A: Yes, we have a formal Data Protection Policy and DPO assigned in line with General Data Protection Regulation (GDPR). Global DPO can be reached out at privacy@wise.com. The latest version of our privacy policy can be found here.
    Q: Please define the monthly uptime percentage of the Wise examined service and how this is achieved. How does Wise resolve service downtime that may affect transfers?
    A: Wise endeavour to ensure we have a highly available platform that both our direct customers and partners can rely on. This is achieved by a team of hundreds of engineers who work to ensure the reliability of the service offered. Unfortunately, incidents can still happen and any disruptions will be posted on our status page and you can also sign up for incident and upcoming maintenance notifications by contacting us.
    Q: What is Wise expecting as an API Token mechanism from the calling client? Please provide details on how to generate an API token with Wise.
    A: Please find below the links with detail for the token generation in each different scenario. User authorization for existing accounts
    Sign up new users via API (available for bank integrations only)
    User tokens
    Refresh user access token