Appearance
Forms — Collecting Data
When the API needs input from your users, it provides a form. Forms are resources with the form profile that include a JSON Schema (draft 2020-12) in their inputs field. The schema describes exactly what data to collect.
The Form Lifecycle
- GET the form URL (discovered from a link) to receive the schema
- Collect data from the user based on the schema
- POST the data back to the same URL
- Follow the 303 redirect to the resulting resource
Example: Insurance Quote Request Form
When you follow a request-insurance-quote link, you receive a form:
http
GET /insurance-quote-request?data=eyJ0eX... HTTP/1.1
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
Link: <tag:flywire.com,2016:agents:api:profile:hypermedia>;rel="profile"
Link: <tag:flywire.com,2016:agents:api:profile:form>;rel="profile"json
{
"inputs": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"adults": {
"type": "integer",
"default": 1
},
"children": {
"type": "integer",
"default": 0
},
"policy_start_date": {
"type": "string",
"format": "date"
},
"policy_end_date": {
"type": "string",
"format": "date"
},
"nationality": {
"type": "string",
"oneOf": [
{ "const": "CN", "title": "China" },
{ "const": "IN", "title": "India" },
{ "const": "VN", "title": "Vietnam" }
]
}
},
"required": ["adults", "policy_start_date", "policy_end_date", "nationality"]
},
"links": [
{ "rel": "self", "href": "https://..." },
{ "rel": "tag:flywire.com,2016:agents:api:relation:insurance-types", "href": "https://..." }
]
}Reading the Schema
| Schema feature | Meaning |
|---|---|
type: "string" | A text value |
type: "integer" | A whole number |
format: "date" | An ISO 8601 date (YYYY-MM-DD) |
oneOf with const + title | A dropdown — const is the value to submit, title is the display label |
required array | Fields that must be present in the POST body |
default | A pre-filled value (the user can change it) |
TIP
The inputs schema is a standard JSON Schema. You can use any JSON Schema library to validate user input before submitting.
Submitting the Form
POST the collected data as JSON to the same URL you used to GET the form:
http
POST /insurance-quote-request?data=eyJ0eX... HTTP/1.1
Content-Type: application/json
Accept: application/json
{
"adults": 1,
"children": 0,
"policy_start_date": "2026-06-01",
"policy_end_date": "2027-05-31",
"nationality": "CN"
}The 303 Redirect
A successful submission returns 303 See Other with a Location header pointing to the created resource:
http
HTTP/1.1 303 See Other
Location: https://api-platform.demo.flywire.com/agents/v2/insurance-quotes?data=eyJ...The Location target collection (insurance-quotes, plural) is the resource the form created; the form itself was at the singular insurance-quote-request. This singular/plural split is consistent across the API: forms POST to a *-request endpoint and redirect to the plural collection.
Follow the redirect (your HTTP client may do this automatically) to get the resulting resource — in this case, an insurance quote.
307 vs 303
The standard-payment-experience relation responds to its no-body POST with 307 Temporary Redirect rather than 303. The two codes differ in how the redirect should be followed: 303 changes the method to GET on the target, while 307 preserves the original method (POST). The experience target only supports GET, so when you handle a 307 follow it explicitly with a GET against the Location header rather than relying on your client's default redirect behaviour.
WARNING
If validation fails, the API returns a response with a 4xx status code and details about what went wrong. Always check the response status before following a redirect.
Forms with Defaults
Some form links include pre-filled defaults from e.g. a previous step. For example, the adjust-insurance-quote form pre-fills the original quote parameters so the user only changes what they need. The default values come from the server — use them to pre-populate your UI.