Transfer Creation

Once a quote and recipient have been created, you are ready to create a transfer. Creating a transfer returns a complete transfer object, which includes the final details with all final details, including the final required pay in amount to process the transfer.

Different integration types will require different transfer types to be created. All transfers may require additional transfer requirements, which should be requested and captured before creation of the transfer.

Once ready to create a transfer, your application should use one of the following transfer creation types:

  • Regular Transfer - Used for most integrations and for personal tokens
  • Third Party Transfer - Used for only those partners that operate on a Third Party Infrastructure model.
  • Partner License Transfer - Used for only those partners that operate on a partner license model
Only one type of transfer creation will be made available for your integration, with others resulting in a 403 - Unauthorized response. If you feel this is incorrect, please speak with the Wise team.

Each transfer can have additional requirements that are needed in order to process the transfer. To determine the transfer requirements needed, your application should use the transfer requirements endpoints to request the requirements for the transfer.

Requirements are returned in a dynamic form, with form types, restrictions, and validation included in a consistent method. This allows your application to present these to users in a consistent way.

Once all transfer requirements have been gathered, they should be added to the details section of the create transfer API call.

For a full reference, please see the request transfer requirements API reference.

Including transfer requirements that are not optional is important, as it helps ensure that transfers are able to process as quickly as possible with further requests for information reduced. Please ensure that this process is part of your integration.

It is important to update the quote before creating a transfer as fees and expected delivery time can change based on the recipient, payout method, or payment meta data.

For example, the fees and delivery estimate are different in the case of sending USD to a country other than the USA - we call this Global USD. Multiple factors can play into this, so it is important to complete this step.

Updating the quote ensures you can show the customer the correct final price and delivery estimate time before they commit to creating and funding the transfer.

Please see the update quote API reference for full details on how to complete this update.

Updating a quote with a recipient ID is not a required step, and in certain integrations is not necessary. Our team will help determine if this step can be removed from your application.
Transfer Nature is a required field that should always be patched to a quote for transfers to and from BRL. This ensures the correct IOF tax is applied.

POST /v1/transfers

Request
sourceAccount (optional)integer

Refund recipient account ID

targetAccountinteger

Recipient account ID. You can create multiple transfers to same recipient account.

quoteUuidtext

V2 quote ID. You can only create one transfer per one quote. You cannot use same quote ID to create multiple transfers.

customerTransactionIduuid

This is required to perform idempotency check to avoid duplicate transfers in case of network failures or timeouts.

details.referencetext

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.

details.transferPurpose (conditionally required)text

For example when target currency is THB. See more about conditions at Transfers.Requirements

details.transferPurposeSubTransferPurpose (conditionally required)text

For example when target currency is CNY. See more about conditions at Transfers.Requirements

details.transferPurposeInvoiceNumber (conditionally required)text

For example when target currency is INR. See more about conditions at Transfers.Requirements

details.sourceOfFunds (conditionally required)text

For example when target currency is USD and transfer amount exceeds 80k. See more about conditions at Transfers.Requirements

There are two options to deal with conditionally required fields:

  • Always call transfer-requirements endpoint and submit values only if indicated so.
  • Always provide values for these fields based on a dynamically retrieved list (transfer-requirements endpoint). It is possible these fields change over time so hard coding the options does create some risk of issues. Contact api@wise.com if you have questions about this property, especially if considering hardcoding a value.

Response

Returns a standard transfer object.

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.

Payment Approvals

If your business account has payment approvals, your application will run in to this error when attempting to create a transfer

Quote cannot be accepted with this request due to missing approval.

Consider removing the payment rule if you are going to use the API to create transfers.

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": <quote ID>,
"customerTransactionId": "<the unique identifier you generated for the transfer attempt>",
"details" : {
"reference" : "to my friend",
"transferPurpose": "verification.transfers.purpose.pay.bills",
"transferPurposeSubTransferPurpose": "verification.sub.transfers.purpose.pay.interpretation.service"
"sourceOfFunds": "verification.source.of.funds.other"
}
}'

POST /v2/profiles/{{profileId}}/third-party-transfers

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

  • Originator datablock is additionally required
  • Depending on the legal entity type of the originator (PRIVATE or BUSINESS), the required fields vary. Please refer the two sample request examples on the right.
  • OriginalTransferId field is being used instead of customerTransactionId
Request
targetAccountinteger

Recipient account ID. You can create multiple transfers to same recipient account.

quotetext

V2 quote ID. You can only create one transfer per one quote.
You cannot use same quote ID to create multiple transfers.

originalTransferIdtext

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.

details.reference (optional)text

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.

originatorgroup

Data block to capture payment originator details.

originator.legalEntityTypetext

PRIVATE or BUSINESS. Payment originator legal type.

originator.referencetext

Unique customer ID in your system. This allows us to uniquely identify each originator. Required.

originator.nametext

Data block to capture the originator name details.
Depends on the type of legal entity (PRIVATE or BUSINESS), the required fields and inputs are different.

originator.name.givenNametext

Payment originator first name. Required if legalEntityType = PRIVATE.

originator.name.middleNames (optional)text array

Payment originator middle name(s). Used only if legalEntityType = PRIVATE.

originator.name.familyNametext

Payment originator family name. Required if legalEntityType = PRIVATE.

originator.name.patronymicName (optional)text

Payment originator patronymic name. Used only if legalEntityType = PRIVATE.

originator.name.fullNametext

Payment originator full legal name. Required if legalEntityType = BUSINESS.

originator.dateOfBirthyyyy-mm-dd

Payment originator date of birth. Required if legalEntityType = PRIVATE.

originator.businessRegistrationCodetext

Payment originator business registry number / incorporation number. Required if legalEntityType = BUSINESS.

originator.address.firstLinetext

Payment originator address first line. Required

originator.address.citytext

Payment originator address city. Required

originator.address.stateCodetext

Payment originator address state code. Required if address country code in (US, CA, BR, AU). See Countries and states

originator.address.countryCodetext

Payment originator address first line. Required

originator.address.postCode (optional)text

Originator address zip code.

Response

Returns an originator transfer object.

You need to save the transfer ID for tracking its status later via webhooks.

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.

Example Request - Personal
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>,
"quote": "<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 - 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>,
"quote": "<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"
}
}
}'

POST /v1/profiles/{{profileId}}/partner-licence-transfers

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

  • originator datablock is additionally required
Request
sourceAccount (optional)integer

Refund recipient account ID.

targetAccountinteger

Recipient account ID. You can create multiple transfers to same recipient account.

quotetext

V2 quote ID. You can only create one transfer per one quote.
You cannot use same quote ID to create multiple transfers.

customerTransactionIdtext

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

details.reference (optional)text

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.

originatorgroup

Data block to capture payment originator details.

originator.legalEntityTypetext

PRIVATE or BUSINESS. Payment originator legal type.

originator.externalIdtext

Unique customer ID in your system. This allows us to uniquely identify each originator. Required.

originator.name.givenNametext

Payment originator first name. Required if legalEntityType = PRIVATE.

originator.name.middleNamestext array

Payment originator middle name(s). Used only if legalEntityType = PRIVATE. Optional

originator.name.familyNametext

Payment originator family name. Required if legalEntityType = PRIVATE.

originator.name.patronymicNametext

Payment originator patronymic name. Used only if legalEntityType = PRIVATE. Optional

originator.name.fullNametext

Payment originator full legal name. Required if legalEntityType = BUSINESS.

originator.dateOfBirthyyyy-mm-dd

Payment originator date of birth. Required if legalEntityType = PRIVATE.

originator.businessRegistrationCodetext

Payment originator business registry number / incorporation number. Required if legalEntityType = BUSINESS.

originator.address.firstLinetext

Payment originator address first line. Required

originator.address.citytext

Payment originator address city. Required

originator.address.stateCodetext

Payment originator address state code. Required if address country code in (US, CA, BR, AU). See Countries and states

originator.address.countryCodetext

Payment originator address first line. Required

originator.address.postCodetext

Originator address zip code. Optional

Response

Returns an originator transfer object.

You need to save the transfer ID for tracking its status later via webhooks.

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.

Example Request - Personal
curl -X POST https://api.sandbox.transferwise.tech/v1/profiles/{{profileId}}/partner-licence-transfers \
-H 'Authorization: Bearer <your api token>' \
-H 'Content-Type: application/json' \
-d '{
"sourceAccount": <refund recipient account ID>,
"targetAccount": <recipient account ID>,
"quote": "<quote ID>",
"customerTransactionId": "<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 - Business
curl -X POST https://api.sandbox.transferwise.tech/v1/profiles/{{profileId}}/partner-licence-transfers \
-H 'Authorization: Bearer <your api token>' \
-H 'Content-Type: application/json' \
-d '{
"sourceAccount": <refund recipient account ID>,
"targetAccount": <recipient account ID>,
"quote": "<quote ID>",
"customerTransactionId": "<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"
}
}
}'

Testing in Sandbox

Because Sandbox is a test environment, there are some differences between Sandbox and Production. Please keep these in mind as you test.

We've outlined the differences between the Sandbox and Production environments for quotes, recipient creation, and funding in the relevant sections. For all other functionalities, including transfer creation, you can test in Sandbox using the same methods as in Production.

Speak with the Wise team if you have further questions about testing transfers in Sandbox.