Skip to content

Create a Payment Experience ​

This flow walks you through generating a shareable payment link for your client. You start at the root, browse payment recipients, pick a destination, and receive a URL that the payer can use to complete their payment.

Step 1 — Get the Root ​

bash
curl 'https://api-platform.demo.flywire.com/agents/v2/' \
  --header 'X-Authentication-Key: YOUR_API_TOKEN'
python
import requests
TOKEN = "YOUR_API_TOKEN"
HEADERS = {"X-Authentication-Key": TOKEN}
root = requests.get("https://api-platform.demo.flywire.com/agents/v2/", headers=HEADERS).json()
javascript
const TOKEN = "YOUR_API_TOKEN";
const HEADERS = { "X-Authentication-Key": TOKEN };
const root = await fetch("https://api-platform.demo.flywire.com/agents/v2/", { headers: HEADERS }).then(r => r.json());

Step 2 — Follow payment-recipients ​

Find the link whose rel ends with payment-recipients and GET its href.

bash
curl "$PAYMENT_RECIPIENTS_HREF" \
  --header 'X-Authentication-Key: YOUR_API_TOKEN'
python
recipients_link = next(
    l for l in root["links"]
    if l["rel"].endswith("payment-recipients")
)
recipients = requests.get(recipients_link["href"], headers=HEADERS).json()
javascript
const recipientsLink = root.links.find(
  l => l.rel.endsWith("payment-recipients")
);
const recipients = await fetch(recipientsLink.href, { headers: HEADERS })
  .then(r => r.json());

The response contains an items array. Each item has a name, description, and links.

Step 3 — Navigate the Recipient Tree ​

Items come in two flavours:

TypeHas country?Key link
GroupNopayment-recipients — drill down into sub-items
DestinationYesset-up-payment-experience or standard-payment-experience
Decision tree
  1. Look at an item's properties.
  2. No country field → it's a group. Follow its payment-recipients link to get child items.
  3. Has country field → it's a destination. Proceed to Step 4.

For groups, follow the payment-recipients link the same way you did in Step 2, and repeat until you reach a destination. Note the index of the destination within its parent collection — you'll need it in Step 4 to find the right action link.

Items don't carry their own links array

Action links for an item (such as standard-payment-experience) are emitted on the parent collection's links[], each carrying an anchor field like "#/items/0". To find the action for item N, search the collection's links[] for a link whose rel matches and whose anchor equals #/items/N. See Anchoring.

python
# Find the first destination in the current `recipients` collection.
# In real code, you'd let the user pick — here we take the first.
destination_idx, destination = next(
    (i, it) for i, it in enumerate(recipients["items"]) if "country" in it
)
javascript
const destinationIdx = recipients.items.findIndex(it => "country" in it);
const destination = recipients.items[destinationIdx];

Step 4 — Create the Payment Experience ​

Once you have a destination, check which link is available:

Option A — standard-payment-experience ​

No setup required. POST directly (empty body) and you'll receive a 307 Temporary Redirect to the prepared experience. Unlike a 303, a 307 preserves the POST method when followed — most HTTP clients handle this automatically with redirect: "follow" (fetch) or -L (curl).

bash
curl -X POST "$STANDARD_EXPERIENCE_HREF" \
  --header 'X-Authentication-Key: YOUR_API_TOKEN' \
  -L
python
anchor = f"#/items/{destination_idx}"
exp_link = next(
    l for l in recipients["links"]
    if l["rel"].endswith("standard-payment-experience")
    and l.get("anchor") == anchor
)
experience = requests.post(exp_link["href"], headers=HEADERS).json()
javascript
const anchor = `#/items/${destinationIdx}`;
const expLink = recipients.links.find(
  l => l.rel.endsWith("standard-payment-experience") && l.anchor === anchor
);
const experience = await fetch(expLink.href, {
  method: "POST", headers: HEADERS, redirect: "follow"
}).then(r => r.json());

Option B — set-up-payment-experience ​

The destination requires additional data before a payment experience can be created.

  1. GET the set-up-payment-experience link to receive a form with an inputs schema.
  2. Build a JSON body that satisfies the schema.
  3. POST the body back to the same URL.
  4. Follow the 303 redirect to get the payment experience.
bash
# 1. Get the form
curl "$SETUP_HREF" --header 'X-Authentication-Key: YOUR_API_TOKEN'

# 2. Post the filled form (follow redirect)
curl -X POST "$SETUP_HREF" \
  --header 'X-Authentication-Key: YOUR_API_TOKEN' \
  --header 'Content-Type: application/json' \
  -d '{"amount": {"value": 1500, "currency": "USD"}}' \
  -L
python
anchor = f"#/items/{destination_idx}"
setup_link = next(
    l for l in recipients["links"]
    if l["rel"].endswith("set-up-payment-experience")
    and l.get("anchor") == anchor
)
form = requests.get(setup_link["href"], headers=HEADERS).json()

experience = requests.post(
    setup_link["href"],
    headers={**HEADERS, "Content-Type": "application/json"},
    json={"amount": {"value": 1500, "currency": "USD"}}
).json()
javascript
const anchor = `#/items/${destinationIdx}`;
const setupLink = recipients.links.find(
  l => l.rel.endsWith("set-up-payment-experience") && l.anchor === anchor
);
const form = await fetch(setupLink.href, { headers: HEADERS })
  .then(r => r.json());

const experience = await fetch(setupLink.href, {
  method: "POST",
  headers: { ...HEADERS, "Content-Type": "application/json" },
  body: JSON.stringify({ amount: { value: 1500, currency: "USD" } }),
  redirect: "follow"
}).then(r => r.json());

WARNING

The inputs schema varies by destination. Always read the form before constructing your POST body.

The payment experience response contains a payment link. This is the URL you share with your client.

json
{
  "created": "2026-03-20T14:30:00Z",
  "destination": { "name": "Demo University", "country": "US", "route": "tuition" },
  "links": [
    { "rel": "tag:flywire.com,2016:agents:api:relation:payment", "href": "https://payment.demo.flywire.com/..." }
  ]
}

TIP

The payment link is a full URL pointing to the Flywire payment portal. The payer opens it in their browser to complete the payment.

Flywire Agents API Documentation