API reference / Applications

post/v1/applications/{id}/submit

Submit to the destination authority

Operation
submitApplication
Authentication
API key

Moves an application from **paid** to submitted. A draft is a 409 — an application that has not been paid for must not be sent to a government.

Scoped to the authenticated tenant. Keys issued to one tenant can never read or modify another tenant’s resources.

**Operational note for integrators:** no government in our four markets currently offers a third-party submission API, so behind this endpoint a human submits through the official portal. Do not treat a 200 as proof the government has accepted anything — watch for the status transition instead.

Request

Parameters

idpathrequiredstring

Responses

200Submitted.
idstringrequired
referencestringrequired

Safe to read aloud.

example: HV-QYFHW6M4D8

product_idstringrequired
nationality_iso3stringrequired
destination_iso3stringrequired

one of: ETHSOMDJIKEN

statusstringrequired

one of: draftawaiting_paymentpaidsubmittedunder_reviewapprovedrejectedcancelledexpired

form_dataobjectrequired

The applicant’s own answers, keyed by the wizard’s field paths: `personal.*`, `passport.*`, `contact.*`, `travel.*`, `accommodation.*`, `purpose.*`, `host.*`, `family.*`, `employment.*`, `emergency.*`, plus a `documents` array. **Partial by design** — the wizard autosaves the whole object as the applicant types, so a draft holds only the fields filled in so far, and a `PATCH` merges rather than replaces. Which fields apply depends on the destination and on earlier answers. Unknown keys are accepted and ignored; `extensions` is the map that is validated strictly.

extensionsobjectrequired

Answers the destination’s own form asks for and ours does not. Validated against the captured flow for this destination — an unrecognised key is refused, because a field the government will read is not a place to accept a typo. See `packages/reference`.

travellersobject[]required

Everyone travelling with the applicant — the applicant is not in this list. Empty for a single-traveller application, which is every application created before groups existed. Set at creation and frozen with the price, because the party size is what the price is for.

pricing_snapshotobjectrequired

The price agreed at creation, frozen. A later government fee change must never re-price an in-flight application, and a dispute months later has to be answerable from this row. `travellers` in here is the party size **including the lead**, and the fees are per person — the total is their product.

versionintegerrequired

Optimistic concurrency token. Send the version you last saw on a PATCH.

government_referencestringnullrequired
submitted_atstringnullrequired
decided_atstringnullrequired
created_atstringrequired
updated_atstringrequired
400The request body or query failed validation.
errorobjectrequired
401No key, an unknown key, a revoked key, or a key whose tenant is not active. All four return an identical body on purpose: distinguishing them would let a caller discover which partners we have.
errorobjectrequired
403The key is valid but does not hold the scope this route requires.
errorobjectrequired
404Not found, or not yours. A resource belonging to another tenant answers 404 rather than 403, because 403 would confirm the record exists.
errorobjectrequired

Example

curl
curl -X POST https://api.haavisa.com/v1/applications/<id>/submit \
  -H "Authorization: Bearer $HAAVISA_API_KEY"

More in Applications

Something unclear? The eligibility guide explains the model behind the answers; the errors guide covers the envelope.