Introduction

Travsify is one REST API for the entire travel stack — flights, hotels, tours, transfers, e-Visas and insurance. You ship one integration; we keep 6 supplier connections live for you and pay your wallet the difference between supplier price and your selling price.

6
Travel verticals · one schema
< 800ms
P95 search latency
2
Currencies · USD & NGN wallet
Who this guide is for
Anyone building a travel product — even if you've never touched an airline API. We assume you know how to send an HTTP request. That's it.

The one-liner

One line of code. Any language. Live data. Travsify is a plain REST API — every language on Earth can speak HTTP, so the entire travel stack is one HTTP call away. Pick your stack, paste the line, swap in your key. That's the integration.

curl
curl -X POST https://travsify.com/api/v1/flights/search -H "Authorization: Bearer tsk_sandbox_your_key_here" -H "Content-Type: application/json" -d '{"origin":"LOS","destination":"DXB","departure_date":"2026-06-01","adults":1}'
Why this works everywhere
Travsify is REST + JSON over HTTPS — the universal language of the web. There is nothing to install, no SDK to import, no native dependency. If your runtime can make an HTTP request (and they all can), you have access to every flight, hotel, tour, transfer, e-Visa and insurance plan we connect to.
13+
Languages · same one line
0
SDK installs required
1
Header. 1 endpoint. 1 key.

5-minute quickstart

You can call the sandbox the moment you sign up — no KYB required to start building.

  1. 1
    Create an account
    Go to signup. The moment you confirm your email, your sandbox API key is issued automatically.
  2. 2
    Grab your sandbox key
    Open Dashboard → API keys. Copy the key that starts with tsk_sandbox_.
  3. 3
    Make your first call
    bash
    curl -X POST https://travsify.com/api/v1/flights/search \
      -H "Authorization: Bearer tsk_sandbox_your_key_here" \
      -H "Content-Type: application/json" \
      -d '{
        "origin": "LOS",
        "destination": "DXB",
        "departure_date": "2026-06-01",
        "adults": 1
      }'
  4. 4
    Book from the dashboard
    Want to test a paid booking? Fund your USD wallet (Stripe) or NGN wallet (bank transfer) with $10, then use Dashboard → Book to confirm a real flight or hotel.
That's it — you're integrated
Sandbox returns the same JSON shape as live. When you're ready, swap your key prefix fromtsk_sandbox_totsk_live_and you're in production.

Authentication

Every request needs a bearer token in the Authorization header. Two key types — both available from your dashboard:

Sandbox key
tsk_sandbox_
Free. Issued at signup. Identical responses to live, no real money moves.
Live key
tsk_live_
Production traffic. Issued the moment your KYB is approved.
bash
curl https://travsify.com/api/v1/health \
  -H "Authorization: Bearer tsk_sandbox_your_key_here"
Keep keys server-side
Never ship live keys in browser bundles or mobile apps. If a key ever leaks, revoke it fromDashboard → API keys.

Wallet & funding

Every booking — sandbox or live, dashboard or API — is paid from your Travsify wallet. No post-paid billing, no surprise invoices. You see exactly what each booking cost before you confirm.

  • USD wallet — fund with card via Stripe, withdraw to any USD bank.
  • NGN wallet — fund via bank transfer to your dedicated Fincra virtual account, withdraw to any NGN bank.
  • Wallet balance is debited automatically on booking; refunds credit back the same way.
  • Your partner markup on each booking is paid into your wallet as profit, available for withdrawal.
How a booking flows
  1. Customer books on your site → you call /orders
  2. We debit provider price + Travsify markup from your wallet
  3. We credit your partner markup back as wallet profit
  4. You charge your customer whatever you want — you keep 100% of that

Markups & pricing

Every price you see includes two layers of markup added on top of the supplier base price:

1. Travsify markup
Set by us per vertical. Covers supplier connection + platform.
2. Your partner markup
You set per vertical from Dashboard → Markups. Paid to your wallet.
json
// Every price response includes the breakdown
{
  "base_price": 800,
  "price": 870,
  "price_breakdown": {
    "provider_base": 800,
    "travsify_markup": 40,
    "partner_markup": 30,
    "total": 870,
    "currency": "USD"
  }
}

Catalog (live inventory)

One endpoint to populate every dropdown on your frontend — countries, cities, destinations, providers — directly from our live database. Don't copy this data into your own DB. Call it on page load (or cache it for a few minutes) so your selectors always reflect what we currently have inventory for, including new corridors we add.

GET/api/v1/catalog
Request
json
// Optional: filter to one vertical
GET /api/v1/catalog?vertical=tours

// Verticals: tours | visas | transfers | rentals | insurance
Response
json
{
  "data": {
    "tours": {
      "total_items": 1339,
      "countries": [
        { "country": "United Arab Emirates", "cities": ["Abu Dhabi", "Dubai"] }
      ]
    },
    "visas": {
      "total_items": 412,
      "destinations": [
        {
          "destination": "AE",
          "destination_name": "United Arab Emirates",
          "nationalities": ["NG", "US", "GB"],
          "visa_types": ["tourist", "transit"]
        }
      ]
    },
    "transfers":  { "total_items": 0, "countries": [] },
    "rentals":    { "total_items": 0, "countries": [] },
    "insurance":  { "total_items": 12, "providers": ["SafetyWing"], "plans": [] }
  },
  "generated_at": "2026-04-28T10:00:00.000Z"
}
Use it from the SDK
js
const t = Travsify.init("tsk_sandbox_...");

// Populate a country dropdown for tours
const { tours } = (await t.catalog("tours")).data;
const countries = tours.countries.map(c => c.country);

// Or fetch every vertical at once
const all = await t.catalog();
Why this matters
We keep adding countries and destinations to our backend every week. As long as you read from/api/v1/catalog, your users see the new inventory the moment we publish it — no redeploy, no DB migration, no code change on your side.

Flights

Live NDC + GDS inventory via Duffel. Real seat maps, real-time confirmation, instant tickets.

POST/api/v1/flights/search
Request
json
{
  "origin": "LOS",
  "destination": "DXB",
  "departure_date": "2026-06-01",
  "return_date": "2026-06-12",
  "adults": 1
}
Response
json
{
  "data": {
    "offers": [{
      "id": "off_0001",
      "owner": "Emirates",
      "total_amount": "812.40",
      "total_currency": "USD"
    }]
  }
}
POST/api/v1/flights/orders
Request
json
{
  "offer_id": "off_0001",
  "passengers": [{
    "title": "mr",
    "given_name": "Ada",
    "family_name": "Lovelace",
    "born_on": "1992-04-12",
    "gender": "f",
    "email": "ada@example.com",
    "phone_number": "+2348012345678"
  }]
}
Response
json
{
  "data": {
    "booking_id": "bkg_01H...",
    "reference": "TSF-FLT-9X2K",
    "status": "confirmed",
    "ticket_numbers": ["176-1234567890"]
  }
}

Hotels

2M+ properties via LiteAPI — instant confirmation, daily price refresh, cancellation policies included.

POST/api/v1/hotels/search
Request
json
{
  "country_code": "AE",
  "checkin": "2026-06-12",
  "checkout": "2026-06-15",
  "adults": 2,
  "currency": "USD"
}
Response
json
{
  "data": {
    "hotels": [{
      "id": "lp_5512",
      "name": "Atlantis The Royal",
      "stars": 5,
      "price": 940,
      "currency": "USD",
      "offer_id": "ofr_..."
    }]
  }
}
POST/api/v1/hotels/bookings
Request
json
{
  "offer_id": "ofr_...",
  "holder": { "firstName": "Ada", "lastName": "Lovelace", "email": "ada@example.com" },
  "guests": [{ "firstName": "Ada", "lastName": "Lovelace" }]
}
Response
json
{ "data": { "booking_id": "bkg_...", "reference": "TSF-HTL-...", "status": "confirmed" } }

Tours & activities

GetYourGuide affiliate inventory. Same unified API — your customers stay on your brand.

POST/api/v1/tours/search
Request
json
{ "destination": "Dubai", "date": "2026-06-13", "participants": 2 }
Response
json
{ "data": { "tours": [{ "id": "gyg_...", "title": "Burj Khalifa fast-track", "price": 89, "currency": "USD" }] } }
POST/api/v1/tours/bookings
Request
json
{ "tour_id": "gyg_...", "participants": [{ "firstName": "Ada", "lastName": "Lovelace", "email": "ada@example.com" }] }
Response
json
{ "data": { "booking_id": "bkg_...", "status": "processing" } }

Transfers

Mozio worldwide ground transport — sedans, vans, shuttles. Affiliate, fully wrapped.

POST/api/v1/transfers/search
Request
json
{ "pickup": "DXB Airport", "dropoff": "Atlantis The Royal", "datetime": "2026-06-12T18:30", "passengers": 2 }
Response
json
{ "data": { "transfers": [{ "id": "moz_...", "vehicle": "Sedan", "price": 65, "currency": "USD" }] } }

e-Visas

Sherpa-powered visa eligibility + e-Visa application via affiliate. We handle fulfilment.

POST/api/v1/visas/search
Request
json
{ "nationality": "NG", "destination": "AE", "purpose": "tourism" }
Response
json
{ "data": { "visas": [{ "id": "shp_...", "name": "UAE 30-day eVisa", "price": 75, "currency": "USD" }] } }

Insurance

SafetyWing travel medical & trip insurance — quote and bind in one call.

POST/api/v1/insurance/search
Request
json
{ "nationality": "NG", "destination": "AE", "start_date": "2026-06-12", "end_date": "2026-06-19", "travelers": 1 }
Response
json
{ "data": { "plans": [{ "id": "sw_...", "name": "Nomad Insurance", "price": 42, "currency": "USD" }] } }

Webhooks

We push events to your endpoint in real time. Configure your URL from the dashboard, then verify the signature header on every request.

Event types
  • booking.confirmed — supplier confirmed
  • booking.cancelled — cancelled by you or supplier
  • booking.refunded — money returned to wallet
  • booking.fulfilled — affiliate verticals only
  • wallet.credited — funds arrived
  • payout.completed — withdrawal paid
javascript
// Verify the signature in your handler
import crypto from "crypto";

function verify(signatureHeader, rawBody, secret) {
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(signatureHeader), Buffer.from(expected));
}

Errors & retries

Errors are JSON. Status codes follow standard HTTP semantics.

CodeMeaningWhat to do
400validation_errorFix the field highlighted in error.message and retry.
401invalid_api_keyCheck the Authorization header. Re-issue from dashboard if needed.
402wallet_insufficientTop up your wallet then retry. We never auto-charge cards.
404offer_expiredSearch again — flight/hotel offers expire after ~15 minutes.
429rate_limitedBack off using the Retry-After header. Default limit: 120 req/min.
5xxprovider_errorIdempotent retry safe. Use the same Idempotency-Key header.
Idempotency
Send Idempotency-Key: <uuid> on every write call. We deduplicate retries for 24 hours so a network blip never double-books or double-charges.

Going live

Four things to tick off before you flip the switch:

  1. 1
    Submit KYB
    Open Dashboard → Profile. Reviews complete in 24–72 hours.
  2. 2
    Set your markups
    Configure per-vertical partner markup at Dashboard → Markups.
  3. 3
    Fund your wallet
    Top up USD or NGN at Dashboard → Wallet. Even $10 unlocks live bookings.
  4. 4
    Swap your key
    Replace tsk_sandbox_ with tsk_live_ in your environment. Done.