Offers

Endpoints

About this resource

When to use this resource

Use the Offers resource to retrieve the prices Flywire offers for a payment and show your payer a price in their own currency.

You can request offers for the payment amount in your currency and show the payer the amount in their own currency instead of only yours. Each offer returned by the API includes the payment method, the amount the payer pays, the exchange rate applied, and the adjustments (such as surcharges) that apply to that offer (the Response section lists every field). Each offer has a limited lifespan, returned in the expires_at parameter, and is held at a frozen exchange rate (if applicable) until then, so request a new offer when you show a price instead of storing it for later.

For example, a payer in Germany is viewing a service priced at 1,200.00 USD. Use the Requesting offers endpoint with amount_to set to 120000, country set to DE and currency_from set to EUR. The offers in the response show the amount the payer pays in euros.

What is an offer?

An offer is the price for an available payment method (credit card, bank transfer, etc.) for a payment.

Example: the payer needs to pay 5,000 USD for tuition, one of the offers is "Pay 4,300 CNY via Bank Transfer". The offer tells the payer what they have to pay, including FX rates and fees if those apply.

The offers that are available for a payment depends on a combination of the following factors:

  • The chosen recipient.

  • The country or countries involved in the payment (for example, paying from China to the US).

  • The amount of money being paid.

All offers have a limited lifespan and a frozen exchange rate (if applicable)

All offers returned from the Offers resource are frozen offers. This means that the foreign exchange rate (if applicable) is guaranteed for the lifespan of the offer.

Offers have a limited lifespan. The exact expiration time is provided in the offer's expires_at parameter.

Automatic adjustment calculation when you provide a tokenized card

When requesting offers using a tokenized card (payment_method_token), any adjustments that apply to the offer (such as surcharges) are automatically calculated and returned directly in the response's adjustments array.

Requesting offers

This endpoint returns the available offers for a payment scenario. Depending on whether your payer is introducing a new payment method or using a previously saved payment method, the endpoint operates in one of two mutually exclusive integration modes: direct mode or tokenized mode.

Direct mode

Use this mode when requesting offers for a payer who has not yet stored or selected a payment method.

  • Required context: you must provide the recipient ID (recipient_id), the amount you want to receive (amount_to), and the payer's ISO country code (country).

  • Optional filters: you can optionally pass currency_from to specify a source currency, type to filter available offers by payment method type (e.g., card or direct_debit), or recurring (true or false) to specify whether the returned offers support recurring payments.

  • Use case: the payer is using a payment method that you have not tokenized, or if your flow requires that you display all available payment offers to the payer.

Tokenized mode

Currently, retrieving offers using tokenized mode supports card tokens only.

Use this mode when requesting offers for returning payers who have a stored payment method.

  • Required context: you must provide the recipient ID (recipient_id), the amount you want to receive (amount_to), the payment_method_token, and the payor_id.

  • Automatic resolution: the API automatically retrieves the stored payment method details behind the scenes to derive the payer's country, payment type, and any adjustments that may apply to the offer.

  • Optional parameters and currency resolution:

    • Optionally pass mandate_id to evaluate offers against a recurring agreement. The source currency is inferred automatically from the mandate.

    • Optionally pass currency_from to filter offers manually when requesting offers for a one-time payment using a stored payment method.

    • Optionally pass recurring (true or false) to specify whether the returned offers support recurring payments.

  • Use case: the payer is paying with a payment method that you have previously tokenized.

Parameter mutual exclusivity rules

  • Do not pass type alongside a payment_method_token (it is inferred from the token).

  • Do not pass currency_from alongside a mandate_id (the currency is inferred automatically from the mandate).

Request

Overview

Use the direct request mode when evaluating offers for one-off payments where no stored token exists.

Parameters for the Request Body

POST/payments/v1/offers

curl https://base-url-placeholder/offers
  -X POST
  -H "Content-Type: application/json"
  -H "X-Authentication-Key: {api_key}"
  -d '{
    "recipient_id": "FWU",
    "amount_to": 120000,
    "country": "US",
    "currency_from": "USD",
    "type": "card",
    "recurring": false
}'

Overview

Currently, retrieving offers using tokenized mode supports card tokens only.

Tokenized mode retrieves offers using a stored payment method (payment_method_token) and a payer identifier (payor_id). In this mode, the payment method type is inferred automatically from the tokenized payment method and must be omitted from the request body.

Currency resolution options

When submitting a request in tokenized mode, you can optionally specify the payment currency using one of two mutually exclusive methods:

  • Mandate-locked currency: include mandate_id to evaluate offers against a recurring agreement. The source currency is inferred automatically from the mandate.

  • Explicit currency: include currency_from to force offers to be returned for a specific currency.

    For example, if your payment flow requires you to provide offers that are quoted to the payer in USD, you would set "currency_from": "USD".

  • Constraint: you can pass either a mandate ID or an explicit currency code, but you must not include both parameters in the same request. Passing both fields triggers a 422 Unprocessable Entity validation error.

Parameters for the Request Body

POST/payments/v1/offers

curl https://base-url-placeholder/offers
  -X POST
  -H "Content-Type: application/json"
  -H "X-Authentication-Key: {api_key}"
  -d '{
    "recipient_id": "FWU",
    "amount_to": 100000,
    "payment_method_token": "a1b2c3d4e5f67890abcd",
    "payor_id": "Payer123",
    "mandate_id": "MCFWU20260430HaB7fKMg",
    "recurring": true
}'

Response

payment_method_settings object

Returned for card-based offers that accept multiple brands or card types.

Omitted for single-brand offers or non-card payment methods.

adjustments array

Contains price modifications for the offer. Returns an empty array if no adjustments apply.

[
    {
        "id": "06164af3-2671-486e-ba4e-2df20df6bed5",
        "name": "American Express in USD",
        "type": "card",
        "expires_at": "2026-08-14T15:08:51Z",
        "recurring": false,
        "amount_from": 120000,
        "currency_from": "USD",
        "amount_to": 120000,
        "currency_to": "USD",
        "exchange_rate": 1.0,
        "adjustments": []
    },
    {
        "id": "01a000b6-2118-7d73-b6fd-330e2b6becbd",
        "name": "Debit/Credit Card in USD",
        "type": "card",
        "expires_at": "2026-08-14T15:08:51Z",
        "recurring": false,
        "amount_from": 120000,
        "currency_from": "USD",
        "amount_to": 120000,
        "currency_to": "USD",
        "exchange_rate": 1.0,
        "payment_method_settings": {
            "accepted_brands": [
                "VISA",
                "MC"
            ],
            "accepted_card_classification": [
                "DEBIT",
                "CREDIT"
            ]
        },
        "adjustments": []
    }
]

404 Error - resource not found

When does this happen?

In tokenized mode, the payment method token, mandate, or associated payor data could not be found. The 404 is generic and does not specify which resource was missing.

What should you do?

  1. Verify that the payment_method_token, payor_id, and (if provided) mandate_id are all valid.
  2. Confirm that the payment method token has not been deleted.
  3. If using a mandate, verify that the mandate exists and is associated with the token and payer ID you provided.
{
    "type": "https://developers.flywire.com",
    "title": "Not Found",
    "status": 404,
    "detail": "Not found"
}

422 Error - missing or invalid required parameter

When does this happen?

You didn't provide a required parameter, or provided one with an invalid value.

For POST /offers, the required parameters are:

  • recipient_id: your recipient ID
  • amount_to: a positive integer representing the amount in the smallest currency unit
  • In direct mode: country (ISO 3166-1 alpha-2 code, e.g. "US")
  • In tokenized mode: payment_method_token and payor_id together

What should you do?

The error response tells you which parameter is missing or invalid.

Check your request:

  • Verify you've included all required parameters for the mode you're using.

  • For amount_to, ensure it's an integer greater than 0 (e.g., 10000 for $100 USD, not 100.00).

  • For country in direct mode, use a valid ISO 3166-1 alpha-2 code.

  • For recipient_id, verify it matches the identifier of one of your recipients, and uses the required format.

{
    "type": "https://developers.flywire.com",
    "title": "Unprocessable Entity",
    "status": 422,
    "detail": "Invalid parameters",
    "errors": [
        {
            "type": "invalid_param",
            "source": "/",
            "param": "amount_to",
            "message": "must be greater than 0"
        }
    ]
}

422 Error - cannot provide type with payment_method_token

When does this happen?

In tokenized mode, you passed both a payment_method_token and type. When using a saved payment method token, the type is already known from the token itself and must not be specified again in the request.

What should you do?

Remove the type parameter from your request. The payment method type will be determined from the token you provide.

{
    "type": "https://developers.flywire.com",
    "title": "Unprocessable Entity",
    "status": 422,
    "detail": "Invalid parameters",
    "errors": [
        {
            "type": "invalid_param",
            "source": "/",
            "param": "type",
            "message": "cannot be provided together with payment_method_token"
        }
    ]
}

422 Error - payment_method_token and payor_id must be provided together

When does this happen?

In tokenized mode, you provided one of payment_method_token or payor_id without the other. Both are required to retrieve an offers using a tokenized payment method.

What should you do?

Ensure both parameters are present in your request.

{
    "type": "https://developers.flywire.com",
    "title": "Unprocessable Entity",
    "status": 422,
    "detail": "Invalid parameters",
    "errors": [
        {
            "type": "invalid_param",
            "source": "/",
            "param": "payor_id",
            "message": "is missing"
        }
    ]
}

422 Error - invalid recipient

When does this happen?

The recipient_id you provided does not exist, is not active, or is for a recipient that you are not authorized to access.

What should you do?

  • Verify that your recipient_id is spelled correctly and matches exactly a recipient code assigned to you.

  • Check with your Flywire contact to confirm the recipient code is active.

  • Ensure you're using the recipient code assigned by Flywire, not the recipient name or any other identifier.

{
    "type": "https://developers.flywire.com",
    "title": "Unprocessable Entity",
    "status": 422,
    "detail": "Invalid parameters",
    "errors": [
        {
            "type": "invalid_param",
            "source": "/recipient_id",
            "param": "recipient_id",
            "message": "This recipient is either non-existing or has been deactivated"
        }
    ]
}

422 Error - invalid mandate_id combination

When does this happen?

You provided mandate_id in an invalid combination with other parameters.

Mandates have two requirements:

  • mandate_id requires both payment_method_token and payor_id to be present (i.e., you can only use a mandate in tokenized mode).
  • mandate_id cannot be provided together with currency_from (the mandate itself determines the currency).

What should you do?

Ensure your request follows one of these patterns:

  • With a mandate: include payment_method_token, payor_id, and mandate_id, but omit currency_from.
  • Without a mandate: omit mandate_id entirely, and provide currency_from if needed.
{
    "type": "https://developers.flywire.com",
    "title": "Unprocessable Entity",
    "status": 422,
    "detail": "Invalid parameters",
    "errors": [
        {
            "type": "invalid_param",
            "source": "/",
            "param": "mandate_id",
            "message": "cannot be provided together with currency_from"
        }
    ]
}

503 Error- Service Unavailable

When does this happen?

The server is currently unavailable. This is typically a temporary state, often due to maintenance or server overload.

What should you do?

Try the request again after some time.

{
  "type": "https://developers.flywire.com",
  "status": "503",
  "title": "Service Unavailable"
}

Retrieving a specific offer

Use this endpoint to retrieve the details of an offer you previously received from Requesting offers, using its offer ID.

The response uses the same schema as Requesting offers.

Request

How to Resolve the Path Placeholders of the Endpoint

Exchange {offerId} in the endpoint with the offer ID.

Parameters for the Request Body

No request body needed.

GET/payments/v1/offers/{offerId}

curl https://base-url-placeholder/offers/01a000b6-2118-7d73-b6fd-330e2b6becbd
  -X GET
  -H "Content-Type: application/json"
  -H "X-Authentication-Key: {api_key}"

Response

payment_method_settings object

Returned for card-based offers that accept multiple brands or card types.

Omitted for single-brand offers or non-card payment methods.

adjustments array

Contains price modifications for the offer. Returns an empty array if no adjustments apply.

{
    "id": "01a000b6-2118-7d73-b6fd-330e2b6becbd",
    "name": "Debit/Credit Card in USD",
    "type": "card",
    "expires_at": "2026-08-14T15:08:51Z",
    "recurring": false,
    "amount_from": 115811,
    "currency_from": "USD",
    "amount_to": 100000,
    "currency_to": "EUR",
    "exchange_rate": 0.863475836,
    "payment_method_settings": {
        "accepted_brands": [
            "VISA",
            "MC"
        ],
        "accepted_card_classification": [
            "DEBIT",
            "CREDIT"
        ]
    },
    "adjustments": []
}

404 Error - offer expired (path)

When does this happen?

This occurs when you provide an offer ID in your request's {offerId} path parameter for an offer that has expired.

An offer expires once its expires_at time has passed.

What should you do?

Ensure that you provided a valid offer ID in your request.

  • Check the expires_at parameter from the original offer response to confirm that the offer's lifespan has ended.

  • The API does not allow you to update or extend the validity of an expired offer.

  • To proceed with the payment, you must use a new offer.

    You can retrieve offers using the Requesting offers endpoint.

{
    "type": "https://developers.flywire.com",
    "title": "Not Found",
    "status": 404,
    "detail": "Not found"
}

422 Error - invalid offer ID (path)

When does this happen?

This occurs when you provide an invalid offer ID in your request's {offerId} path parameter.

What should you do?

Ensure that you provided a valid offer ID in your request.

The offer ID is a string of characters that uniquely identifies a specific offer.

Example format: 06164af3-2671-486e-ba4e-2df20df6bed5

The offer ID is in the response after you created an offer (in the parameter id).

Refer to Requesting offers for more information.

{
    "type": "https://developers.flywire.com",
    "title": "Unprocessable entity",
    "status": 422,
    "detail": "Invalid parameters",
    "errors": [
        {
            "source": "/",
            "param": "offer_id",
            "type": "invalid_param",
            "message": "is not a valid UUID v7"
        }
    ]
}

503 Error- Service Unavailable

When does this happen?

The server is currently unavailable. This is typically a temporary state, often due to maintenance or server overload.

What should you do?

Try the request again after some time.

{
  "type": "https://developers.flywire.com",
  "status": "503",
  "title": "Service Unavailable"
}