Deals API

Publish a round-trip flight deal with a single HTTP request, authenticated with a shared key. Publishing is treated as the key-holder's own assertion that the fare was checked at the booking page - verifiedAt is required, not inferred. Publishing again for the same origin and destination (e.g. a weekly re-check) replaces the existing listing rather than creating a duplicate.

Publish a deal

POST https://fareletter.com/api/deals
Content-Type: application/json
Authorization: Bearer <your key>

FieldRequiredNotes
originyesDeparture airport code: DEL, BOM, BLR, CCU or MAA
destCodeyesDestination airport code, e.g. BKK
destyesDestination city name, e.g. "Bangkok"
imgyesA valid http(s) image URL for the deal's cover photo
priceNyesThe fare, as a number (e.g. 18400 for ₹18,400)
usualNyesThe usual/reference price, as a number; must be >= priceN
daysyesTrip length, e.g. "8 days"
windowyesTravel window, e.g. "Feb 2027"
airlineyesAirline(s), e.g. "IndiGo"
stopsyese.g. "Non-stop" or "1 stop each way"
vianoConnection note, e.g. "via Kuala Lumpur (KUL)"
datesyesAn example date range, e.g. "9 - 16 Feb 2027"
bagyesBaggage note, e.g. "7 kg cabin bag; check-in extra"
datePairsnoUp to 6 [dates, price] pairs for the month/budget filter; defaults to a single pair built from dates/priceN
verifiedAtyesISO date you checked the fare at the booking page, e.g. "2026-10-25"

Request example

{
  "origin": "DEL",
  "destCode": "BKK",
  "dest": "Bangkok",
  "img": "https://example.com/bangkok.jpg",
  "priceN": 18400,
  "usualN": 26000,
  "days": "8 days",
  "window": "Feb 2027",
  "airline": "Air India Express",
  "stops": "Non-stop",
  "dates": "9 - 16 Feb 2027",
  "bag": "7 kg cabin bag; check-in extra",
  "verifiedAt": "2026-10-25"
}

Success response - 201 Created

{
  "ok": true,
  "id": "del-bkk",
  "url": "https://fareletter.com/deal/del-bkk",
  "cities": "Delhi to Bangkok",
  "price": "₹18,400",
  "usual": "₹26,000",
  "verifiedAt": "2026-10-25"
}

Errors

StatuserrorWhen
400validationA field fails the rules above - the response includes a fields object naming each problem
400invalid_jsonBody isn't valid JSON
401unauthorizedMissing or wrong Authorization: Bearer key
413payload_too_largeRequest body over ~20,000 bytes
415unsupported_media_typeContent-Type isn't application/json
429rate_limitedMore than 20 publishes from the same IP in an hour

List deals

GET https://fareletter.com/api/deals returns every listed deal as JSON, including its page url.

curl example

curl -X POST https://fareletter.com/api/deals \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_KEY" \
  -d '{"origin":"DEL","destCode":"BKK","dest":"Bangkok","img":"https://example.com/bangkok.jpg","priceN":18400,"usualN":26000,"days":"8 days","window":"Feb 2027","airline":"Air India Express","stops":"Non-stop","dates":"9 - 16 Feb 2027","bag":"7 kg cabin bag; check-in extra","verifiedAt":"2026-10-25"}'

Limits

See the deals