musafir.comVisa API
How it worksTry itCatalogueOrdersTrackingSandboxFAQDocs
Request early access
Private beta, credentials issued per partner

Sell visas to your customers. A travel visa API in six endpoints.

Search a priced catalogue, create the whole party in one call, attach documents, submit. We handle the consulate and tell you when the decision lands. You keep the customer, the brand and the margin.

Request early accessRead the API docs
  • No visa expertise needed
  • No card payments to take
  • Sandbox before production
catalogue-search.shcURL
curl -X POST "$MUSAFIR_VISA_API/v1/catalogue/search" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "destination": "AE",
    "travelDate": "2026-11-20",
    "travellers": [
      { "ref": "t1", "type": "ADT", "nationality": "IN", "residency": "AE" }
    ]
  }'
200 OKJSON
{
  "destination": { "code": "AE", "name": "United Arab Emirates" },
  "advisory": null,
  "products": [
    {
      "productId": "AE_EV_ADT",
      "title": "UAE 30 Day Tourist Visa",
      "bookable": true,
      "processingDays": 4,
      "supportedTravellerTypes": ["ADT", "CHD"],
      "pricing": { "amount": 380, "currency": "AED", "firm": false }
    }
  ]
}
68Destinations, priced and sellable
20+Years processing visas
1.6M+Visas processed
98.2%Historical approval rate
Definition

What is a travel visa API?

A travel visa API lets travel agencies, airlines, OTAs and travel platforms offer visa services inside their own website or app. It returns visa options, requirements and pricing for a given traveller, creates applications, accepts documents and reports application status, without the platform building its own visa processing operation.

What is the Musafir Visa API?

The Musafir Visa API is a partner interface to Musafir's visa processing platform, which has handled over 1.6 million visa applications and runs visa services on musafir.com today. Partners search a priced catalogue, create an order for the whole party, upload documents, submit, and receive decisions by webhook, while Musafir handles documents and consulate processing. It is published for developers as the JETT Visa Partner API, with the full reference at developers.jett.travel. The API is in private beta and credentials are issued per partner.

musafir.com

Others

Visa MCP

© 2026 Musafir.com. All rights reserved.

Musafir.com is a private travel and tourism agency. We are not a government authority or an official government website. Visa applications can also be made directly with the relevant government authority or its official portal. Final visa approval rests solely with the issuing immigration authority.

How a visa API works

  1. 1Search the catalogue for what this party can buy, at your contracted price.
  2. 2Read the documents and form fields that product needs, per traveller.
  3. 3Create the order for the whole party in one call, passports included.
  4. 4Upload each traveller's documents, then submit the order.
  5. 5Track it, and take the decision on a webhook.

Musafir Visa API at a glance

Who it is forTravel agencies, OTAs, airlines, TMCs and tour operators
IntegrationREST, JSON. Six endpoints from catalogue to submitted application
AuthenticationClient credentials. Scoped bearer token, one hour, no refresh
Scopescatalogue:read, orders:write, orders:read. Request a narrower token any time
CataloguePriced per partner, resolved by nationality, residency and travel date
Eligibility rulesAnswered per traveller, so you can name which one is the problem
DocumentsPer-product checklists with guideline and template files. Uploads to 10 MB
OrdersThe whole party in one call, passports included. No partial orders
IdempotencyRequired on every write. A replayed key returns the first response
StatuswaitingOn says whose court the ball is in, on every order read
WebhooksAction required, decision, status change, order completed or cancelled
SettlementStatement per period, totalled per currency and never converted
SandboxIts own environment, reserved test inputs, and a status mover for decisions
BrandingWhite-label. The partner keeps the customer and the brand
Also published asJETT Visa Partner API, the same product for developers
DocumentationPublished in full at developers.jett.travel
AvailabilityPrivate beta. Credentials issued per partner
Why this is hard

Visas are where international bookings quietly die.

Not because the product is complicated — because the operation behind it is. That operation is the thing we are handing you.

The rules never sit still

Eligibility, fees and document lists change by nationality, by residency and by consulate, and they change without notice. Keeping a visa rulebook current is a full-time operation, not a feature.

Documents kill the booking

Chasing passport scans over email is where an international booking quietly dies. Every day between intent and submission is a cancellation waiting to happen.

Nobody owns the status

Once an application leaves your hands you have nothing to tell the traveller, until they call. Support absorbs a cost that should never have existed.

How it works

Six endpoints and you're selling.

Token, catalogue, requirements, order, documents, submit. That is the integration. Everything that makes visas hard sits on our side of the line.

sell-a-visa.shcURL
# 0. A token. One hour, no refresh, scopes ride inside it.
curl -X POST "$MUSAFIR_VISA_API/v1/auth/token" \
  -H "Content-Type: application/json" \
  -d '{"clientId":"...","clientSecret":"..."}'

# 1. What can this party buy, and what does it cost you?
curl -X POST "$MUSAFIR_VISA_API/v1/catalogue/search" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"destination":"AE","travelDate":"2026-11-20",
       "travellers":[{"ref":"t1","type":"ADT","nationality":"IN"}]}'

# 2. Create the whole party in one call. Passports ride along.
curl -X POST "$MUSAFIR_VISA_API/v1/orders" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: 8f14e45f-ea2b-4c1d-9f3a-77b1c0d2e9a4" \
  -d @order.json

# 3. Attach each document, then submit.
curl -X POST "$MUSAFIR_VISA_API/v1/orders/$ORDER/travellers/t1/documents/PASSPORT" \
  -H "Authorization: Bearer $TOKEN" -F "file=@passport.jpg"
curl -X POST "$MUSAFIR_VISA_API/v1/orders/$ORDER/submit" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: 2c7a91be-5f30-4d18-b0e2-6a4d8c1f7b93"

# 4. We take it from here. The decision arrives on your webhook.
  • No rulebook to maintain

    Eligibility, fees and document lists differ by nationality, residency and consulate, and they move without notice. That is our problem, and the answer arrives in the catalogue response.

  • No checklist to guess at

    Requirements are published per traveller, per product, with the guideline and template files attached. Build your collection screen from the response instead of a list you have to keep current.

  • No payments to take

    Orders draw against a credit line and settle on invoice. You never handle a visa fee, so the API adds nothing to your PCI scope.

Try it

Change the traveller. Watch the rules move.

This is our live catalogue, the same eligibility rules, prices and document lists running musafir.com right now. Pick a nationality, a residency and a destination, and see what a partner gets back. Some combinations lose a visa entirely. Some change the paperwork. That is the work you are handing us.

Start from a case

Priced options, processing tiers and the document list for this consulate.

A visa is required, and you can sell it

Route
Applied online
To sell
Transit E-Visa · ₹3,299
Show the full answerHide the full answer

12 visas they can buy

  • Transit E-Visa

    Standard · 4–5 days

    ₹3,299
  • Transit E-Visa

    Standard · 4–5 days

    ₹5,299
  • Tourist E-Visa

    Standard · 4–5 days

    ₹7,699
  • Tourist E-Visa

    Standard · 4–5 days

    ₹7,899

Documents this consulate wants from them

Uploaded to us

  • First Page of Passport
  • Last Page of Passport
  • Passport External Cover Page
  • PAN card
  • Photograph
  • Onward Flight Ticket
  • Hotel Booking
  • Additional Document
  • Return Flight Ticket

Change the nationality and watch this list change. Keeping it correct, per profile, per consulate, is the job you are handing us.

catalogue.shcURL
curl -X POST "$MUSAFIR_VISA_API/v1/catalogue/search" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "destination": "AE",
    "travellers": [
      { "ref": "t1", "type": "ADT", "nationality": "IN", "residency": "IN" }
    ]
  }'
200 OKJSON
{
  "destination": "AE",
  "nationality": "IN",
  "residency": "IN",
  "visaRequired": true,
  "currency": "INR",
  "options": [
    {
      "skuId": "019f933e-536e-7507-a8f2-c3b40d03bc91",
      "title": "Transit E-Visa",
      "price": 3299,
      "processing": "Standard",
      "estimatedDays": [
        4,
        5
      ],
      "bookableOnline": true
    },
    {
      "skuId": "019f933e-cf5c-72e0-ae9a-ae07bca0fc88",
      "title": "Transit E-Visa",
      "price": 5299,
      "processing": "Standard",
      "estimatedDays": [
        4,
        5
      ],
      "bookableOnline": true
    },
    {
      "skuId": "019ea64a-23a2-71b7-8841-1ad434ab5046",
      "title": "Tourist E-Visa",
      "price": 7699,
      "processing": "Standard",
      "estimatedDays": [
        4,
        5
      ],
      "bookableOnline": true
    },
    {
      "skuId": "019e8d7b-334a-7652-91fd-eff69bfa61d5",
      "title": "Tourist E-Visa",
      "price": 7899,
      "processing": "Standard",
      "estimatedDays": [
        4,
        5
      ],
      "bookableOnline": true
    },
    {
      "skuId": "019e8d7b-fae7-7436-892a-f0bc0d03b870",
      "title": "Tourist E-Visa",
      "price": 11499,
      "processing": "Express",
      "estimatedDays": [
        2,
        3
      ],
      "bookableOnline": true
    },
    {
      "skuId": "019ea64d-9e9a-71b9-b1b9-c8e4b24e24ea",
      "title": "Tourist E-Visa",
      "price": 13999,
      "processing": "Standard",
      "estimatedDays": [
        4,
        5
      ],
      "bookableOnline": true
    },
    {
      "skuId": "019ea64c-9684-7580-9309-138d926319cb",
      "title": "Tourist E-Visa",
      "price": 14499,
      "processing": "Standard",
      "estimatedDays": [
        4,
        5
      ],
      "bookableOnline": true
    },
    {
      "skuId": "019ea64d-a1ca-75da-8a5a-da71ef00048a",
      "title": "Tourist E-Visa",
      "price": 14999,
      "processing": "Express",
      "estimatedDays": [
        2,
        3
      ],
      "bookableOnline": true
    },
    {
      "skuId": "019ed976-450d-7002-a0f4-6289450c235c",
      "title": "Tourist E-Visa",
      "price": 15999,
      "processing": "Super Express",
      "estimatedDays": [
        1,
        2
      ],
      "bookableOnline": true
    },
    {
      "skuId": "019f89e1-60a1-7442-a618-1e4ff80211c9",
      "title": "Tourist E-Visa",
      "price": 18999,
      "processing": "Instant",
      "estimatedDays": [
        1,
        1
      ],
      "bookableOnline": true
    },
    {
      "skuId": "019ea64d-f61a-72eb-a299-fcc672c7ab81",
      "title": "Tourist E-Visa",
      "price": 21499,
      "processing": "Standard",
      "estimatedDays": [
        4,
        5
      ],
      "bookableOnline": true
    },
    {
      "skuId": "019f5aea-bd9e-71e0-8960-15d65ea6f923",
      "title": "Extension E-Visa",
      "price": 27099,
      "processing": "Standard",
      "estimatedDays": [
        2,
        3
      ],
      "bookableOnline": true
    }
  ],
  "documents": [
    "PASSPORT_FIRST_PAGE",
    "LAST_PASSPORT",
    "PASSPORT_EXTERNAL_COVER_PAGE",
    "PAN_CARD",
    "PHOTO",
    "FLIGHT_TICKET",
    "HOTEL_BOOKING",
    "AD",
    "RETURN-FLIGHT_TICKET"
  ]
}

Real answers from our live catalogue, shaped into the partner response. The partner catalogue endpoint is POST /v1/catalogue/search, documented in full at developers.jett.travel.

01Catalogue

Every visa we can process, priced for you.

Post the party and the travel date. Back comes what those travellers are actually eligible for, with your contracted price, the processing time and the document list the consulate will ask for.

  • Act on bookable. It accounts for the whole request, so a past travel date or a traveller type this product cannot serve both come back false.
  • eligibility[] carries each traveller's own answer, so your agent can name which traveller is the problem rather than say there is one.
  • Prices are what you owe us under contract. Nothing in the API returns a customer-facing price. What you charge is yours to set.
  • The same catalogue that runs musafir.com, so it cannot go stale against our own storefront.
POST /v1/catalogue/search
catalogue-search.shcURL
curl -X POST "$MUSAFIR_VISA_API/v1/catalogue/search" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "destination": "AE",
    "travelDate": "2026-11-20",
    "travellers": [
      { "ref": "t1", "type": "ADT", "nationality": "IN", "residency": "AE" }
    ]
  }'
200 OKJSON
{
  "destination": { "code": 
02Orders

The whole party in one call. Keep the customer.

One insert holds every traveller, every passport and the consent you captured. There is no hosted checkout to redirect into and no card to collect. The order books against your account and settles on invoice.

  • There are no partial orders. Passports ride on the create, because every destination has a blocking passport step and an order without one could never be submitted.
  • Idempotency-Key on every write. A replayed key returns the first response instead of placing a second application.
  • The party is reordered so an adult is traveller one. Address travellers by your own ref, never by position.
  • warnings appears when an order was accepted but something is worth knowing, such as a passport short of the destination's remaining-validity rule.
POST /v1/orders
create-order.shcURL
curl -X POST "$MUSAFIR_VISA_API/v1/orders" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: 8f14e45f-ea2b-4c1d-9f3a-77b1c0d2e9a4" \
  -d '{
    "destination": "AE",
    "productId": "AE_EV_ADT",
    "travelDate": "2026-11-20",
    "partnerCustomerRef": "BOOKING-99213",
    "contact": { "fullName": "Anita Rao", "email": "agent@partner.example" },
    "consent": { "obtainedAt": "2026-09-09T09:15:00Z", "noticeVersion": "2026-06" },
    "travellers": [
      {
        "ref": "t1", "type": "ADT",
        "givenName": "Anita", "familyName": "Rao",
        "dateOfBirth": "1990-04-11", "nationality": "IN", "residency": "AE",
        "passport": {
          "number": "Z1234567", "expiry": "2031-04-10",
          "gender": "F", "placeOfBirth": "Mumbai"
        }
      }
    ]
  }'
201 CreatedJSON
03Documents

Attach the paperwork. Then submit.

Upload each document against the traveller and the document code the requirements call published. Submit runs the same completeness check our own checkout runs, so you find out something is missing before the consulate does.

  • Requirements are per traveller. An adult and a child on one order can be asked for different documents.
  • Files cap at 10 MB, the same ceiling the platform applies, and an oversized file is refused before the upload rather than after it.
  • A 409 on submit names the travellers blocking it, using your own references, so it is a screen you can render rather than a support ticket.
  • A 402 is a credit refusal. Handle it from the first day, not the first time it happens in production.
POST /v1/orders/{id}/.../documents/{code}
documents-and-submit.shcURL
# One call per document, named by your own traveller ref.
curl -X POST \
  "$MUSAFIR_VISA_API/v1/orders/$ORDER/travellers/t1/documents/PASSPORT" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: 6d9b2a10-4c77-4f2e-9a1b-3e5c8d7f0a26" \
  -F "file=@passport.jpg"

# Then submit the order. Empty body.
curl -X POST "$MUSAFIR_VISA_API/v1/orders/$ORDER/submit" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: 2c7a91be-5f30-4d18-b0e2-6a4d8c1f7b93"
04Tracking

Never answer “where’s my visa?” again.

Status is pushed, not polled. Every transition fires a signed webhook, and when the authority decides, the outcome lands on your endpoint. The issued visa is then one call away.

  • Switch on waitingOn, which is partner, jett, embassy or none. status is our internal vocabulary, passed through for display.
  • HMAC-signed over the timestamp and the raw body. Verify it, reply 2xx, and we stop. Anything else retries 24 times across about 18 hours.
  • Events cover action required, decision, status change, order completed and order cancelled.
  • Approved travellers expose the issued visa, refused ones the letter explaining it, where the authority supplied one.
Webhooks

The happy path, in status

  1. OrderCreated
  2. AwaitingDocumentReview
  3. ReadyForSubmission
  4. SubmittedToEmbassy
  5. Approved
  6. Completed
webhookHTTP
POST https://your-app.example.com/webhooks/musafir
X-JETT-Signature: t=1757493262,v1=8a4f2c...
X-JETT-Event-Id: 5f2c9a71d8b34e6f9c1a2b3c4d5e6f70
PayloadJSON
{
  "eventId": "5f2c9a71d8b34e6f9c1a2b3c4d5e6f70",
  "event": "traveller.decision",
  "occurredAt"
Where the line sits

We don’t issue visas. No one but the government does.

Musafir is a licensed visa processing agent. We prepare, submit and track applications with the issuing authority. The decision, whether that is approve, reject or ask for more, belongs to that government alone, and no API changes that. What you can promise your customer is a correct application, submitted quickly, tracked to a decision. Not the decision itself.

What we take off your hands

  • An eligibility-checked, priced catalogue for that exact traveller
  • The document list the consulate actually requires, and validation against it
  • Submission to the consulate, embassy or visa application centre
  • Status through to the decision, plus any document the authority issues
  • Refunds and cancellations, per each destination’s published policy

What no one can sell you

  • A guaranteed approval, or any influence over the decision
  • A processing time faster than the authority’s own
  • A way around biometrics or an in-person appointment where one is mandated
  • A change to government fees, which we pass through unmarked
  • Immigration or legal advice. We process applications, we do not advise on status
The sandbox

Built to be broken, before you build on it.

Its own environment, its own data, and two controls production does not have. Reserved partnerCustomerRef values make a new order play out a set way, and a status mover walks an order to any status as our team or the embassy would. You can write the rejection path without waiting on a consulate to reject something for you.

01

Read the contract

It is published in full, endpoint by endpoint. Nothing is held back for a sales call.

developers.jett.travel
02

Tell us what you'd build

Two minutes on the form below. We reply within two business days with where things stand, not a brochure.

03

Sandbox credentials

Issued per partner, with your sandbox base URL. Production credentials follow once commercial terms are agreed.

Sandbox controls

Force any outcome you need to handle, on demand, so you can write the rejection path without waiting on a consulate to reject something for you. Read the live list of reserved values from the sandbox rather than hardcoding it: reserved inputs and the status mover.

Sandbox inputWhat it forces
partnerCustomerRef: TEST-APPROVEThe order runs through to approved and the webhook fires
partnerCustomerRef: TEST-REJECTThe order is refused, so you can build the refusal path
POST /v1/sandbox/orders/{id}/advanceWalks the order, or one traveller, to any status you name
Idempotency-Key, replayedReturns the first response instead of creating a duplicate

Sandbox tokens are rejected by production and production tokens by the sandbox, so a test order can never touch a real one. The advance and reserved-input routes do not exist in production at all.

Who it’s for

One integration. Four very different businesses.

Travel agencies

Stop couriering passports and queueing at typing centres. Take the application at the counter and let us carry it to the consulate.

Online travel agencies

Attach a visa to every international booking. It is the highest-margin ancillary you are not currently selling.

Airlines

Surface the document requirement before check-in, not at the gate. Fewer denied boardings, one less INAD fine.

Travel management companies

Corporate travellers tracked to a decision, with the policy controls and reporting your clients already expect.

Questions

The awkward ones, answered.

Including the ones we would rather you didn’t ask. If something here isn’t straight enough, tell us and we’ll fix the answer.

Not building an integration

The same catalogue, inside ChatGPT and Claude

Travellers ask their assistant and it reads musafir.com directly — live prices, processing times, document lists and appointment availability. Nothing to build, nothing to sign in to.

Visa MCP

Be one of our first partners

The contract is published and the sandbox is built. Tell us what you would sell and we will get you credentials and a call with the engineers who built it.

We reply within two business days with sandbox credentials or a date for them, an honest read on where the build stands, and a call with the engineers doing it.

"AE"
,
"name"
:
"United Arab Emirates"
}
,
"advisory"
:
null
,
"products"
:
[
{
"productId"
:
"AE_EV_ADT"
,
"title"
:
"UAE 30 Day Tourist Visa"
,
"bookable"
:
true
,
"processingDays"
:
4
,
"supportedTravellerTypes"
:
[
"ADT"
,
"CHD"
]
,
"pricing"
:
{
"amount"
:
380
,
"currency"
:
"AED"
,
"firm"
:
false
}
}
]
}
{ "orderId": "b3f1c2d4e5a6478995ab12cd34ef5678", "orderReference": "VIS-100482", "status": "Draft", "travelDate": "2026-11-20", "partnerCustomerRef": "BOOKING-99213", "travellers": [ { "travellerId": "8a1f4c7e2b9d4a1e8f3c5b7d9e1a2c4b", "ref": "t1", "skuId": "AE_EV_ADT_30D", "type": "ADT", "fullName": "Anita Rao" } ] }
409 ConflictJSON
{
  "code": "conflict",
  "message": "This order is not ready to submit.",
  "traceId": "683c45d7cfe447a2a526985bb992c238",
  "errors": [
    {
      "field": "travellers[t2]",
      "code": "incomplete",
      "message": "Traveller 't2' still has required documents outstanding."
    }
  ]
}
:
"2026-09-10T08:14:22.117Z"
,
"data"
:
{
"orderId"
:
"b3f1c2d4e5a6478995ab12cd34ef5678"
,
"orderReference"
:
"VIS-100482"
,
"travellerId"
:
"8a1f4c7e2b9d4a1e8f3c5b7d9e1a2c4b"
,
"status"
:
"Approved"
,
"previousStatus"
:
"SubmittedToEmbassy"
}
}