JSON Links
For this Pay-By-Link option, you’re creating the link by sending a request to the JSON Link API.
How does it work?
-
Make a request to the API’s base URL.
-
Include an authentication header (otherwise the request will fail).
-
Define the settings for the link in the request body.
-
-
When the request is successful, the API will respond with the link you can give to your payer.
Base URL
Production |
|
Demo |
|
Authentication
All requests to the JSON Link API need to be authenticated with a special header, called the X-Flywire-Digest header. If you leave out the X-Flywire-Digest header, the request will fail.
Hover to highlight the authentication header
curl https://base-url-placeholder/
-X POST
-H "Content-Type: application/json"
-H "X-Flywire-Digest:{your_digest}"
-d '{
"provider": "FWU",
...
}
How to generate the X-Flywire-Digest header
1. Convert the JSON body of your request into a string. Use the exact request body you are using for sending the request.
- Ruby
- .NET
- JavaScript
message_body = your_json_object.to_json
string message_body = JsonConvert.SerializeObject(yourJsonObject);
const message_body = JSON.stringify(yourJsonObject);
2. Generate the header value:
Encrypt the converted body of your request with your Shared Secret using the SHA-256 algorithm.
What is my Shared Secret?
The Shared Secret is a string of characters used for security validations.
For API integration:
Your Shared Secret is used to validate notifications. You receive your Shared Secret together with your API credentials via a secure email after you registered your application.
For other integrations:
Your Shared Secret is used to validate notifications and authenticate requests. You receive your Shared Secret from the Flywire Solutions team after your portal has been set up (please contact the Solutions team in case you don't have your Shared Secret). Note that each portal might have a different shared secret. If you have access to multiple portals, make sure you use the correct shared secret for each portal.
Take the result and encrypt it in Base64.
Use the final result as the value for your digest header.
The examples show you how to do this in different programming languages. In each example, exchange the shared_key with your Shared Secret and message_body with the converted JSON body of your request.
- Ruby
- .NET
- JavaScript
digest = OpenSSL::Digest.new('sha256')
encrypted_payload = OpenSSL::HMAC.digest(digest, shared_secret, notification_body)
Base64.encode64(encrypted_payload).strip
# Step 1: Define the hashing algorithm to use for the HMAC.
# This initializes the SHA-256 hashing mechanism.
hash_algorithm = OpenSSL::Digest.new('sha256')
# Step 2: Compute the HMAC in binary format.
# This uses the shared secret and the message body to produce the HMAC signature.
hmac_binary = OpenSSL::HMAC.digest(hash_algorithm, shared_secret, message_body)
# Step 3: Encode the HMAC in Base64 for use in the X-Flywire-Digest header.
x_flywire_digest = Base64.encode64(hmac_binary).strip
public static string Digest(string shared_secret, string message_body)
{
// Step 1: Initialize the HMACSHA256 object with the shared secret.
// This sets up the hashing algorithm (SHA-256) and the secret key for HMAC.
using (var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(shared_secret)))
{
// Step 2: Convert the message body into a byte array.
// The message body is the message payload you want to hash
var bytes = Encoding.UTF8.GetBytes(message_body);
// Step 3: Compute the HMAC hash of the message body.
// This generates the HMAC using the shared secret and the message body.
var hashedBytes = hmacsha256.ComputeHash(bytes);
// Step 4: Convert the hashed byte array into a Base64 string.
return Convert.ToBase64String(hashedBytes);
}
}
const crypto = require('crypto');
function createDigest(shared_secret, message_body) {
// Step 1: Initialize the HMAC with the SHA-256 algorithm and the shared secret.
const hmac = crypto.createHmac('sha256', shared_secret);
// Step 2: Update the HMAC with the message body.
// The message body is the message payload you want to hash
hmac.update(message_body);
// Step 3: Get the HMAC digest and encode it in Base64.
const digestHeader = hmac.digest('base64');
return digestHeader; // The `digestHeader` is the X-Flywire-Digest header.
}
Request
Portal settings
These parameters are required to properly direct your payer to your unique PayEx portal.
Your logo in the upper left corner tells your payers that they are in your unique PayEx portal:

The recipient ID (also called portal code).
The recipient ID is the unique three-letter ID that identifies the recipient, for example FWU for Flywire University. The recipient ID has been assigned by Flywire when the recipient has been set up.

The unique subdomain for the portal. The subdomain has been provided to you by Flywire when your portal was set up.
Amount settings
It depends on your portal settings if you need to use one amount or multiple items, see Portal setting: Amount or items?.
This example uses one total amount.
Passing the amount can be necessary if your portal settings don't allow the payer to edit the amount field, see Portal setting: Can Payers edit the passed amount?

If your portal doesn't allow payers to edit the amount field, using one total amount (not items), the following can result in a blockage for the payer because the amount will be 0 and not editable, which means the payer will not be able to go through the further steps in your PayEx portal:
-
Passing no amount (since the amount parameter is optional in the request body, the link will successfully be generated, but your payer will be blocked).
-
Passing only max_amount and no amount.
-
Passing an amount that is higher than the max_amount (since this amount contradicts the setting for maximum amount).
If your portal is using items, this does not apply. In all cases above, the amount fields for the items will be 0 but editable for the payer.

The payment amount in the billing currency.

The billing currency is the currency in which the recipient of the payment is billing their payer. The billing currency depends on the
The amount is specified in the smallest unit of the currency, called subunits. For example, in USD, the subunit is cents, and 100 cents equal 1 USD. So, an amount of 12025 (cents) is equivalent to 120.25 USD.
Note that the subunit-to-unit ratio varies by currency, it is not always 100. See Currencies for the subunits of each currency.

The max_amount parameter lets you set the maximum amount you're asking for, allowing your payer to change it to a smaller amount.
This is useful, for allowing partial payments or when the payer might have already partially paid via a different payment. For this reason, you set always set the max_amount to the same amount as the amount (or total amount of all items) - this gives your payer the option to pay less than the amount you are asking for.
If your portal uses items, the maximum amount applies to the sum of all items.
It depends on your portal settings if a payer is allowed to edit the amount you passed. Consider your portal settings before you pass amounts or define a maximum amount.

![]() |
If you pre-filled the amount and the portal setting is that payers can edit the amount, your payer sees an editable field with the amount you passed. Your amount acts as a suggested amount, but the they can enter a different amount, higher or lower. Your portal has general settings for minimal and maximal amounts for payments. The amount your payer enters must be within those settings, otherwise they will get an error. ![]() The settings of a recipient define the minimum and maximum amount for a payment. These limits are defined when you set up the recipient with Flywire. If you didn't customize the settings, the default limits are:
When payments to your recipient contain multiple items, the limits apply to the sum of the amounts of all items.
![]() When you try to create a payment with an amount that is below or above the set limits, you will not be able to create the payment and an error response will be returned. |
![]() |
If you use the max_amount parameter, the field is only editable to the maximum amount you passed. ![]() The max_amount parameter lets you set the maximum amount you're asking for, allowing your payer to change it to a smaller amount. This is useful, for allowing partial payments or when the payer might have already partially paid via a different payment. For this reason, you set always set the max_amount to the same amount as the amount (or total amount of all items) - this gives your payer the option to pay less than the amount you are asking for. If your portal uses items, the maximum amount applies to the sum of all items. |

The amount is specified in the smallest unit of the currency, called subunits. For example, in USD, the subunit is cents, and 100 cents equal 1 USD. So, an amount of 12025 (cents) is equivalent to 120.25 USD.
Note that the subunit-to-unit ratio varies by currency, it is not always 100. See Currencies for the subunits of each currency.
Payer settings

The country code (in ISO 3166-1 alpha-2 format) of the payer's country (meaning the country the money will be sent from).
When you pre-fill fields in your PayEx portal, they are usually displayed as read-only for your payer. However, the country field stays editable so payers can choose their preferred country. This flexibility is important because payers may have bank accounts in multiple countries, not just where they live.
The payer's country in your PayEx portal:
Payer information
Payer information fields contain the details of the payer. The information necessary for Flywire to conduct compliance checks, such as Anti-Money-Laundering (AML). If the payer details are known to you, you can pre-fill the payer fields in your PayEx portal.
The payer information fields in your PayEx portal:

The payer's email address.

The payer's first name.
If the payer is a company or organization, use the organization name as the first name.

The last name (family name) of the payer.
If the payer is a company or organization, use the organization name as the last name.

The first line of the payer's address.
The residential address is required for legal reasons, which is why PO boxes are not permitted.

The payer's city.

The state of the payer in the format of only the second part of the ISO 3166-2 code, for example for US-NY the value is NY.

The payer's zip code.

The phone number of the payer (including the country code).
Use 00 in front of the country code, for example, "0044123456" for country code 44.
When you pre-fill a payer information field, the field will be read-only in your PayEx portal. You can overwrite this behavior and allow your payer to edit pre-filled fields with the allow_to_edit_payer_information parameter.

When you pre-fill a payer information field, the field will be read-only in your PayEx portal. You can overwrite this behavior and allow your payer to edit pre-filled fields with the allow_to_edit_payer_information parameter.
Possible values:
-
true (all pre-filled payer fields are editable)
-
false (default, pre-filled payer fields are read-only)
Dynamic field settings
Fields of a recipient (also called a portal) are fields that are specific to that recipient. Depending on how you use Flywire, you might know them under the names dynamic fields, custom fields, or student fields.
Fields are defined when the recipient (also called portal) is set up by Flywire. They are additional fields that the payer has to fill out when they make their payment (additional to the standard payer fields that are the same for all recipients).
To add, remove or modify your dynamic fields please contact the Solutions team.
dynamic_fields object
Pairs of the id and value of the field:
id |
Depends on your portal settings. You can find out the id of a custom field by checking your portal settings. |
value |
The value you are passing for this field. For more info see Guide for pre-filling dynamic fields. ![]() When you pre-fill fields via a generated link, dynamic fields will be read-only for your payer. This means:
|
Link expiration settings

When does a JSON link expire?
Each JSON link includes a token that determines its expiration:
-
The link expires after a payment is created with it. After that, the payer can track the payment with a different link.
or
-
After the set expiry date (default is 90 days, adjustable via the days_to_expire parameter). The countdown for the expiry date starts immediately after the link is generated.
Changing the expiration time
To define a different expiration time, use any number from 1-90 days. If you don't pass this parameters, the default is 90 days.
Language settings for your PayEx portal

The locale parameter controls the language in which your PayEx portal will be displayed.
If you don't pass this parameter, the default language is English.

Language | Value for locale |
---|---|
English | en |
Spanish | es-ES |
Chinese | zh-CN |
Korean | ko |
Portuguese | pt-PT |
Japanese | ja |
French | fr-FR |
Bahasa Indonesia | id |
Arabic | ar |
Vietnamese | vi |
Italian | it-IT |
German | de-DE |
Payer redirection settings
You can display a button in your PayEx portal that redirects your payer somewhere, for example your website. This button is displayed on the final page of the payment creation process, to the right of the payment instructions.
Your portal might have default settings for the return button and its label. In that case, you don't need to provide a URL in order to display the button. But if there are no default settings and you don't provide a valid URL in the return_cta parameter, the button will not be displayed

The URL payers are directed to when clicking the return button.
Maximal 500 characters.
Your portal might have default settings for the return button and its label. In that case, you don't need to provide a URL in order to display the button. But if there are no default settings and you don't provide a valid URL in the return_cta parameter, the button will not be displayed

The label of the return button. Maximum 500 characters.
If you don't specify a label for your button, the default label "Return to {portal name}" is used.
Callback settings

The notifications URL.
The notifications URL enables you to receive callbacks about the payment status (see Payment Status Notifications).
The notifications URL is the dynamic URL for receiving callbacks.

There are two different URLs for receiving callbacks:
Static URL
For API integrations:
When you set up your application that accesses the Flywire API, you had the option to define a notifications URL. This is the static notifications URL. Callbacks will be sent to this URL for all payments you created via the Flywire API.
The recipient of a payment may also have a static notifications URL defined which might be different from your static notifications URL as a client. In that case, callbacks will also be sent to the recipient's notifications URL.For other integrations:
When you set up your portal together with Flywire, you had the option to define a callback URL for that portal. Callbacks will be sent to this URL for all payments for this portal.
If you don't use a static callback URL yet and want to start using it, please contact the Solutions team.
Dynamic URL
The URL you can set in a parameter when you are creating a payment is the dynamic notifications URL. Since this URL can be different for every payment you create, it is called dynamic.
How defining static and dynamic URLs affect callbacks
![]() |
![]() |
Static URL |
Dynamic URL |
Result |
![]() |
![]() |
You won't receive notifications. |
![]() |
![]() |
You'll receive notifications to your static URL. |
![]() |
![]() |
For API integrations: The dynamic URL will override the static URL and you'll receive notifications only to the dynamic URL. For other integrations: You'll receive callbacks to both URLs. This is called "dual callback URL". A dual callback URL means you defined a static URL in your portal and you are sending callbacks to a different callback URL via the parameter for the payment. In this case, callbacks will be sent to both URLs. This
approach can be useful if you want to update two separate systems.
|
![]() |
![]() |
You'll receive notifications to your dynamic URL |

The external reference (also called callback ID).
The external reference is used to match a notification to a particular payment. You can use any kind of identifier or reference from your own system you might need to identify the payment.
Do I only need to provide an external reference (callback ID) if I provided a callback URL?
Even if you don't provide a callback_url, you might still be receiving callbacks via your static callback URL (set in your portal). In that case, you should provide an external reference, to be able to match the callback to the correct payment.

There are two different URLs for receiving callbacks:
Static URL
For API integrations:
When you set up your application that accesses the Flywire API, you had the option to define a notifications URL. This is the static notifications URL. Callbacks will be sent to this URL for all payments you created via the Flywire API.
The recipient of a payment may also have a static notifications URL defined which might be different from your static notifications URL as a client. In that case, callbacks will also be sent to the recipient's notifications URL.For other integrations:
When you set up your portal together with Flywire, you had the option to define a callback URL for that portal. Callbacks will be sent to this URL for all payments for this portal.
If you don't use a static callback URL yet and want to start using it, please contact the Solutions team.
Dynamic URL
The URL you can set in a parameter when you are creating a payment is the dynamic notifications URL. Since this URL can be different for every payment you create, it is called dynamic.
How defining static and dynamic URLs affect callbacks
![]() |
![]() |
Static URL |
Dynamic URL |
Result |
![]() |
![]() |
You won't receive notifications. |
![]() |
![]() |
You'll receive notifications to your static URL. |
![]() |
![]() |
For API integrations: The dynamic URL will override the static URL and you'll receive notifications only to the dynamic URL. For other integrations: You'll receive callbacks to both URLs. This is called "dual callback URL". A dual callback URL means you defined a static URL in your portal and you are sending callbacks to a different callback URL via the parameter for the payment. In this case, callbacks will be sent to both URLs. This
approach can be useful if you want to update two separate systems.
|
![]() |
![]() |
You'll receive notifications to your dynamic URL |

The version of the callback. Possible values:
-
2 (for version 2)
If you want to receive callbacks, you must provide the callback version and it must be version 2.
For details about callbacks see Payment Status Notifications.
curl https://base-url-placeholder/
-X POST
-H "Content-Type: application/json"
-H "X-Flywire-Digest:{your_digest}"
-d '{
"provider": "FWU",
"payment_destination": "Flywireuniversity",
"amount": 950025,
"max_amount": 950025,
"country": "US",
"sender_email": "[email protected]",
"sender_first_name": "John",
"sender_last_name": "Doe",
"sender_address1": "1 First St",
"sender_city": "London",
"sender_state": "Greater London",
"sender_zip": "SW1 EN3",
"sender_phone": "0044123456789",
"allow_to_edit_payer_information": true,
"dynamic_fields": {
"student_id": "123456",
"student_first_name": "John",
"student_last_name": "Doe"
},
"days_to_expire": "20",
"locale": "es-ES",
"return_cta": "https://www.my-website.com/",
"return_cta_name": "Return to my website",
"callback_url": "https://www.my-callback-system.com/",
"callback_id": "Notifications for Payment 1234",
"callback_version": "2"
}
Parameters that depend on your portal settings
Payment Amount
Portal setting: Amount or items?
When you set up your portal with Flywire, you decided if you always want to get one total amount from a payer or if you want to differentiate between different items (for example, "housing" and "tuition") that each have their own amount. If you want to change this setting, please contact the Solutions team.

If your portal uses items, you have to use the items object to pre-fill the different amount fields for your items.
You can optionally pass the max_amount parameter.
It depends on your portal settings if a payer is allowed to edit the amount you passed. Consider your portal settings before you pass amounts or define a maximum amount.

![]() |
If you pre-filled the amount and the portal setting is that payers can edit the amount, your payer sees an editable field with the amount you passed. Your amount acts as a suggested amount, but the they can enter a different amount, higher or lower. Your portal has general settings for minimal and maximal amounts for payments. The amount your payer enters must be within those settings, otherwise they will get an error. ![]() The settings of a recipient define the minimum and maximum amount for a payment. These limits are defined when you set up the recipient with Flywire. If you didn't customize the settings, the default limits are:
When payments to your recipient contain multiple items, the limits apply to the sum of the amounts of all items.
![]() When you try to create a payment with an amount that is below or above the set limits, you will not be able to create the payment and an error response will be returned. |
![]() |
If you use the max_amount parameter, the field is only editable to the maximum amount you passed. ![]() The max_amount parameter lets you set the maximum amount you're asking for, allowing your payer to change it to a smaller amount. This is useful, for allowing partial payments or when the payer might have already partially paid via a different payment. For this reason, you set always set the max_amount to the same amount as the amount (or total amount of all items) - this gives your payer the option to pay less than the amount you are asking for. If your portal uses items, the maximum amount applies to the sum of all items. |

Parameters
items object
Pairs of the item id and the amount for the item:
id |
Depends on your portal settings. You can find out the id of a payment item by checking your portal settings. |
amount |
The amount for this item in the billing currency, ![]() The billing currency is the currency in which the recipient of the payment is billing their payer. The billing currency depends on the The amount is specified in the smallest unit of the currency, called subunits. For example, in USD, the subunit is cents, and 100 cents equal 1 USD. So, an amount of 12025 (cents) is equivalent to 120.25 USD. Note that the subunit-to-unit ratio varies by currency, it is not always 100. See Currencies for the subunits of each currency. |

The max_amount parameter lets you set the maximum amount you're asking for, allowing your payer to change it to a smaller amount.
This is useful, for allowing partial payments or when the payer might have already partially paid via a different payment. For this reason, you set always set the max_amount to the same amount as the amount (or total amount of all items) - this gives your payer the option to pay less than the amount you are asking for.
If your portal uses items, the maximum amount applies to the sum of all items.
It depends on your portal settings if a payer is allowed to edit the amount you passed. Consider your portal settings before you pass amounts or define a maximum amount.

![]() |
If you pre-filled the amount and the portal setting is that payers can edit the amount, your payer sees an editable field with the amount you passed. Your amount acts as a suggested amount, but the they can enter a different amount, higher or lower. Your portal has general settings for minimal and maximal amounts for payments. The amount your payer enters must be within those settings, otherwise they will get an error. ![]() The settings of a recipient define the minimum and maximum amount for a payment. These limits are defined when you set up the recipient with Flywire. If you didn't customize the settings, the default limits are:
When payments to your recipient contain multiple items, the limits apply to the sum of the amounts of all items.
![]() When you try to create a payment with an amount that is below or above the set limits, you will not be able to create the payment and an error response will be returned. |
![]() |
If you use the max_amount parameter, the field is only editable to the maximum amount you passed. ![]() The max_amount parameter lets you set the maximum amount you're asking for, allowing your payer to change it to a smaller amount. This is useful, for allowing partial payments or when the payer might have already partially paid via a different payment. For this reason, you set always set the max_amount to the same amount as the amount (or total amount of all items) - this gives your payer the option to pay less than the amount you are asking for. If your portal uses items, the maximum amount applies to the sum of all items. |

The amount is specified in the smallest unit of the currency, called subunits. For example, in USD, the subunit is cents, and 100 cents equal 1 USD. So, an amount of 12025 (cents) is equivalent to 120.25 USD.
Note that the subunit-to-unit ratio varies by currency, it is not always 100. See Currencies for the subunits of each currency.
"items": {
"housing": 10000,
"tuition": 20000
},
"max_amount": 30000

If there are no items set up for your portal, you have to use the amount parameter to pre-fill the amount field in your PayEx portal.
Passing an amount is not required in the request body, but you must pass an amount if your portal does not allow the payer to edit the amount field, see Portal setting: Can Payers edit the passed amount?.
You can optionally pass the max_amount parameter.
It depends on your portal settings if a payer is allowed to edit the amount you passed. Consider your portal settings before you pass amounts or define a maximum amount.

![]() |
If you pre-filled the amount and the portal setting is that payers can edit the amount, your payer sees an editable field with the amount you passed. Your amount acts as a suggested amount, but the they can enter a different amount, higher or lower. Your portal has general settings for minimal and maximal amounts for payments. The amount your payer enters must be within those settings, otherwise they will get an error. ![]() The settings of a recipient define the minimum and maximum amount for a payment. These limits are defined when you set up the recipient with Flywire. If you didn't customize the settings, the default limits are:
When payments to your recipient contain multiple items, the limits apply to the sum of the amounts of all items.
![]() When you try to create a payment with an amount that is below or above the set limits, you will not be able to create the payment and an error response will be returned. |
![]() |
If you use the max_amount parameter, the field is only editable to the maximum amount you passed. ![]() The max_amount parameter lets you set the maximum amount you're asking for, allowing your payer to change it to a smaller amount. This is useful, for allowing partial payments or when the payer might have already partially paid via a different payment. For this reason, you set always set the max_amount to the same amount as the amount (or total amount of all items) - this gives your payer the option to pay less than the amount you are asking for. If your portal uses items, the maximum amount applies to the sum of all items. |

Parameters

The payment amount in the billing currency.

The billing currency is the currency in which the recipient of the payment is billing their payer. The billing currency depends on the
The amount is specified in the smallest unit of the currency, called subunits. For example, in USD, the subunit is cents, and 100 cents equal 1 USD. So, an amount of 12025 (cents) is equivalent to 120.25 USD.
Note that the subunit-to-unit ratio varies by currency, it is not always 100. See Currencies for the subunits of each currency.

The max_amount parameter lets you set the maximum amount you're asking for, allowing your payer to change it to a smaller amount.
This is useful, for allowing partial payments or when the payer might have already partially paid via a different payment. For this reason, you set always set the max_amount to the same amount as the amount (or total amount of all items) - this gives your payer the option to pay less than the amount you are asking for.
If your portal uses items, the maximum amount applies to the sum of all items.
It depends on your portal settings if a payer is allowed to edit the amount you passed. Consider your portal settings before you pass amounts or define a maximum amount.

![]() |
If you pre-filled the amount and the portal setting is that payers can edit the amount, your payer sees an editable field with the amount you passed. Your amount acts as a suggested amount, but the they can enter a different amount, higher or lower. Your portal has general settings for minimal and maximal amounts for payments. The amount your payer enters must be within those settings, otherwise they will get an error. ![]() The settings of a recipient define the minimum and maximum amount for a payment. These limits are defined when you set up the recipient with Flywire. If you didn't customize the settings, the default limits are:
When payments to your recipient contain multiple items, the limits apply to the sum of the amounts of all items.
![]() When you try to create a payment with an amount that is below or above the set limits, you will not be able to create the payment and an error response will be returned. |
![]() |
If you use the max_amount parameter, the field is only editable to the maximum amount you passed. ![]() The max_amount parameter lets you set the maximum amount you're asking for, allowing your payer to change it to a smaller amount. This is useful, for allowing partial payments or when the payer might have already partially paid via a different payment. For this reason, you set always set the max_amount to the same amount as the amount (or total amount of all items) - this gives your payer the option to pay less than the amount you are asking for. If your portal uses items, the maximum amount applies to the sum of all items. |

The amount is specified in the smallest unit of the currency, called subunits. For example, in USD, the subunit is cents, and 100 cents equal 1 USD. So, an amount of 12025 (cents) is equivalent to 120.25 USD.
Note that the subunit-to-unit ratio varies by currency, it is not always 100. See Currencies for the subunits of each currency.
"amount": 950025,
"max_amount": 950025
Portal setting: Can Payers edit the passed amount?
When you set up your portal with Flywire, you decided if you want to allow your payers to edit the amount you passed via the generated link. This setting will apply to all links you generate for the portal. If you want to change this setting, please contact the Solutions team.
If my portal does not allow payers to edit the amount, does this mean the amount field in my PayEx portal portal is always read-only for my payers?
No. This setting only applies when a payer followed a link you generated to access your portal. If your portal is accessible through other ways, for example from the Flywire website, the amount field will of course be editable since you didn't pre-fill the field.
What your payer sees after following the link:

![]() |
If you pre-filled the amount and the portal setting is that payers can edit the amount, your payer sees an editable field with the amount you passed. Your amount acts as a suggested amount, but the they can enter a different amount, higher or lower. Your portal has general settings for minimal and maximal amounts for payments. The amount your payer enters must be within those settings, otherwise they will get an error. ![]() The settings of a recipient define the minimum and maximum amount for a payment. These limits are defined when you set up the recipient with Flywire. If you didn't customize the settings, the default limits are:
When payments to your recipient contain multiple items, the limits apply to the sum of the amounts of all items.
![]() When you try to create a payment with an amount that is below or above the set limits, you will not be able to create the payment and an error response will be returned. |
![]() |
If you use the max_amount parameter, the field is only editable to the maximum amount you passed. ![]() The max_amount parameter lets you set the maximum amount you're asking for, allowing your payer to change it to a smaller amount. This is useful, for allowing partial payments or when the payer might have already partially paid via a different payment. For this reason, you set always set the max_amount to the same amount as the amount (or total amount of all items) - this gives your payer the option to pay less than the amount you are asking for. If your portal uses items, the maximum amount applies to the sum of all items. |

Dynamic Fields
What are dynamic fields?
Fields of a recipient (also called a portal) are fields that are specific to that recipient. Depending on how you use Flywire, you might know them under the names dynamic fields, custom fields, or student fields.
Fields are defined when the recipient (also called portal) is set up by Flywire. They are additional fields that the payer has to fill out when they make their payment (additional to the standard payer fields that are the same for all recipients).
Notes for pre-filling dynamic fields
When you pre-fill fields via a generated link, dynamic fields will be read-only for your payer.
This means:
-
For checkboxes, your payer won't be able to select more values or un-select the ones you selected.
-
If you pass invalid values (because of a typo or because the internal name of a value has been changed), the field will be empty and read-only for your payer. If the field is mandatory, this can mean that your payer can't complete the payment. Be careful with passing values that are prone to change.
Guide for pre-filling dynamic fields
- Text
- Dropdown
- Single checkbox
- Multiple checkboxes
Text field
A field to enter text. The field can have different formats:
Free text field |
|
Phone number field |
|
Country dropdown field |
|
Date field |
How to pass values for the different field formats:
Field name:
Use the internal name (Id) of the field. You can check your portal settings to find the Id.
Values:
Free text
Pass the text as a string.
Phone number
The phone number of the payer (including the country code).
Use 00 in front of the country code, for example, "0044123456" for country code 44.
Country
The ISO2 code of the country.
Date
Date in dd/mm/yyyy format, for example 01/01/2025.
"dynamic_fields": {
"student_id": "ID123456",
"phone_number": "0044123456789",
"country_residence": "US",
"start_date": "01/01/2025"
}
Dropdown
A dropdown field with one possible option to pick.
How to pass values for this field type:
Field name:
Use the internal name (Id) of the field. You can check your portal settings to find the Id.
Values:
Pass the internal name (value, not the label of the value) as a string.
If you don't know the internal value for the labels in PayEx, contact the Solutions team.
"dynamic_fields": {
"student_status": "full_time"
}
Single Checkbox
A single checkbox so payers can check it for "yes" or uncheck it for "no"
How to pass values for this field type:
Field name:
Use the internal name (Id) of the field. You can check your portal settings to find the Id.
Values:
Pass either true (checkbox activated) or false (checkbox deactivated), since this is a boolean field.
"dynamic_fields": {
"residential_student": "true"
}
Multiple Checkboxes
Multiple checkboxes so the payer can pick multiple values.
How to pass values for this field type:
Field name:
Use the internal name (Id) of the field. You can check your portal settings to find the Id.
Values:
Pass the internal name (value, not the label of the value) as a string.
If you don't know the internal value for the labels in PayEx, contact the Solutions team.
"dynamic_fields": {
"services_used": "housing, tuition"
}
Response
-
200 Link created
-
400 Malformed JSON
-
401 Unauthorized
-
409 Missing parameter
If your API request was valid, you'll get a "HTTP 200 - Success" response.
In the url parameter you find the link you generated and that you can give to your payer.
How long can the link be used?
Each JSON link includes a token that determines its expiration:
-
The link expires after a payment is created with it. After that, the payer can track the payment with a different link.
or
-
After the set expiry date (default is 90 days, adjustable via the days_to_expire parameter). The countdown for the expiry date starts immediately after the link is generated.
{
"url":"https://payment.flywire.com/orders/4bee6c2c-ae10-465c-ba84-1a978e11681a?token=5e03c2cb-2877-47d8-8226-fbfbf62361b3"
}
400 Error - Malformed JSON
When does this happen?
The request body is not formatted correctly.
What should you do?
Check the request body for formatting errors, for example missing commas.
{
"errors": ["Malformed JSON"],
"url": "https://www.demo.flywire.com/select-school"
}
401 Error - Unauthorized
When does this happen?
The X-Flywire-Digest header is missing or is invalid.
What should you do?
Make sure you use an X-Flywire-Digest header and generate the digest value correctly, see Authentication.
no content
409 Error - Missing Parameters
When does this happen?
You left out required parameters in the request body.
What should you do?
Include the provider and payment_destination parameters in your request.
{
"errors": ["Payment destination can't be blank"],
"url": "https://www.demo.flywire.com/select-school"
}
{
"errors": ["Provider can't be blank"],
"url": "https://payment.demo.flywire.com?destination=TQQ"
}