Notifications from Flywire to you
Flywire supports notifications via callbacks (also known as webhooks). These allow your system to receive real-time notifications about important events.
Payment status notifications are callbacks for payment key events, such as a payment status change.
Using callbacks for payments is optional, but has several benefits:
-
Callbacks can be used to facilitate reconciliation of Flywire payments to accounting systems, ERPs, etc.
-
Callbacks provide real-time updates for payment statuses, no manual checks in Dashboard needed.
-
Callbacks are especially useful for direct debit payments where the payment capture will take a few working days and may be subject to future failure.
-
You can use callbacks to trigger processes that start after the payment is completed.
Enabling callbacks
To enable callbacks, you need to provide a notification URL where Flywire will send HTTP requests. This can be done in two ways:

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 |
Validating Notifications
Validating notifications is optional, as it’s on your server side, but for security reasons it is recommended to validate all notifications.
How to validate a notification
To validate a notification, check its X-Flywire-Digest header. This value is generated by Flywire using your Shared Secret to encrypt the notification body. To verify the notification, generate the digest using the same method and compare it to the X-Flywire-Digest value in the header. If they match, the notification is legitimate and hasn't been tampered with.
-
Retrieve the raw HTTP body of the notification you received.
Make sure you use the raw HTTP body of the notification. You must generate the X-Flywire-Digest value using the exact payload you received in the notification. If you change the body in any way the values won't match later.
-
Encrypt the received notification twice:
1) Encrypt the raw HTTP body of the received notification with your Shared Secret using the SHA-256 algorithm.
2) Take the result and encrypt it in Base64.
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 raw HTTP body of the notification.
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.
- 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. }
-
Compare your Base64 string to the value in the X-Flywire-Digest parameter of the notification you received.
If the values match, the notification came from Flywire and hasn't been changed by a third party.
If the values don't match, you shouldn't trust the notification.