Fortrip

Examples

The whole booking flow over HTTP, in curl, TypeScript and Python. Each example is a file that is checked against the contract.

Every example sends the same request in all three languages. Run one with FORTRIP_TOKEN set to a Fortrip access token. The ids are placeholders: use the ones the previous answer gave you. The TypeScript examples use fetch on Node.js, and the Python examples use httpx.

Sign in

The API page describes the OAuth device flow. This script runs it against GET /v1/auth/config and prints an access token.

#!/usr/bin/env bash
# Sign in with the OAuth device flow and print an access token.
# Needs curl and jq. Prints the access token; export it as FORTRIP_TOKEN.
set -euo pipefail

config=$(curl -sS --fail-with-body --max-time 60 "https://api.fortrip.ai/v1/auth/config")
client_id=$(jq -r .clientId <<<"$config")
token_endpoint=$(jq -r .tokenEndpoint <<<"$config")

device=$(curl -sS --fail-with-body --max-time 60 "$(jq -r .deviceAuthorizationEndpoint <<<"$config")" \
  -d client_id="$client_id" \
  --data-urlencode scope="$(jq -r .scopes <<<"$config")")
device_code=$(jq -r '.device_code // empty' <<<"$device")
if [ -z "$device_code" ]; then
  echo "No device_code in the answer: $device" >&2
  exit 1
fi
echo "Open $(jq -r '.verification_uri_complete // .verification_uri' <<<"$device") and approve the sign-in." >&2

interval=$(jq -r '.interval // 5' <<<"$device")
deadline=$((SECONDS + $(jq -r '.expires_in // 600' <<<"$device")))

while [ "$SECONDS" -lt "$deadline" ]; do
  sleep "$interval"
  token=$(curl -sS --max-time 60 "$token_endpoint" \
    -d grant_type=urn:ietf:params:oauth:grant-type:device_code \
    -d device_code="$device_code" \
    -d client_id="$client_id")
  case "$(jq -r '.error // empty' <<<"$token")" in
    "") jq -r .access_token <<<"$token"; exit 0 ;;
    authorization_pending) ;;
    slow_down) interval=$((interval + 5)) ;;
    *) echo "$token" >&2; exit 1 ;;
  esac
done
echo "The sign-in expired before it was approved. Run this again." >&2
exit 1
#!/usr/bin/env bash
# Search hotels in a city.
# Needs FORTRIP_TOKEN, a Fortrip access token (see device-login).
set -euo pipefail

curl -sS --fail-with-body --max-time 60 -X POST "https://api.fortrip.ai/v1/hotels/search" \
  -H "Authorization: Bearer $FORTRIP_TOKEN" \
  -H "Content-Type: application/json" \
  --data @- <<'JSON'
{
  "destination": {
    "kind": "place_name",
    "name": "Kyoto",
    "countryCode": "JP"
  },
  "stay": {
    "checkIn": "2027-03-10",
    "checkOut": "2027-03-12",
    "rooms": [
      {
        "adults": 2,
        "childrenAges": []
      }
    ]
  },
  "filters": {
    "amenities": [
      "wifi"
    ]
  },
  "sort": "price_asc"
}
JSON

Offers

#!/usr/bin/env bash
# Get live offers for a hotel.
# Needs FORTRIP_TOKEN, a Fortrip access token (see device-login).
set -euo pipefail

curl -sS --fail-with-body --max-time 60 -X POST "https://api.fortrip.ai/v1/hotels/offers" \
  -H "Authorization: Bearer $FORTRIP_TOKEN" \
  -H "Content-Type: application/json" \
  --data @- <<'JSON'
{
  "hotelIds": [
    "htl_Qm3xK9vT2pLw7Hn4Rb8Z"
  ],
  "stay": {
    "checkIn": "2027-03-10",
    "checkOut": "2027-03-12",
    "rooms": [
      {
        "adults": 2,
        "childrenAges": []
      }
    ]
  },
  "filters": {
    "requireFreeCancellation": true
  }
}
JSON

Order

Ordering charges nothing. The answer is an order awaiting_payment; show the user the total and every term, and wait for a clear yes before anyone pays. See orders and payment.

#!/usr/bin/env bash
# Create an order from an offer. Nothing is charged until it is paid.
# Needs FORTRIP_TOKEN, a Fortrip access token (see device-login).
set -euo pipefail

curl -sS --fail-with-body --max-time 60 -X POST "https://api.fortrip.ai/v1/orders" \
  -H "Authorization: Bearer $FORTRIP_TOKEN" \
  -H "Content-Type: application/json" \
  --data @- <<'JSON'
{
  "contact": {
    "firstName": "Ada",
    "lastName": "Lovelace",
    "email": "ada@example.com",
    "phone": "+14155550132"
  },
  "items": [
    {
      "offerId": "off_Bz6yN1cD5fGh8JkM2pQs",
      "hotel": {
        "rooms": [
          {
            "guests": [
              {
                "firstName": "Ada",
                "lastName": "Lovelace"
              },
              {
                "firstName": "Charles",
                "lastName": "Babbage"
              }
            ]
          }
        ]
      }
    }
  ]
}
JSON

Pay

An order is paid one way only. Orders and payment says which ways an order offers and when each applies; the examples below send each request.

The payment link needs no request: give the user the order's payment.url. Read it from the order.

#!/usr/bin/env bash
# Read an order, and print the link to pay it (payment_link) when it awaits payment.
# Needs FORTRIP_TOKEN, a Fortrip access token (see device-login).
set -euo pipefail

link=$(curl -sS --fail-with-body --max-time 60 "https://api.fortrip.ai/v1/orders/ord_Wr4tY7uI0oPa3SdF6gHj" \
  -H "Authorization: Bearer $FORTRIP_TOKEN" \
  | jq -r '.payment.url // empty')
if [ -z "$link" ]; then
  echo "The order has no payment link: it is not awaiting payment, or read it again." >&2
  exit 1
fi
echo "$link"

Shared payment token

#!/usr/bin/env bash
# Pay an order with a Stripe shared payment token.
# Needs FORTRIP_TOKEN, a Fortrip access token (see device-login).
set -euo pipefail

curl -sS --fail-with-body --max-time 60 -X POST "https://api.fortrip.ai/v1/orders/ord_Wr4tY7uI0oPa3SdF6gHj/pay" \
  -H "Authorization: Bearer $FORTRIP_TOKEN" \
  -H "Content-Type: application/json" \
  --data @- <<'JSON'
{
  "sharedPaymentToken": "spt_ExampleTokenFromTheUsersLinkWallet",
  "total": {
    "amount": "132.40",
    "currency": "USD"
  }
}
JSON

Alipay or WeChat Pay

#!/usr/bin/env bash
# Pay an order with Alipay or WeChat Pay: opens the payment.
# Needs FORTRIP_TOKEN, a Fortrip access token (see device-login).
set -euo pipefail

curl -sS --fail-with-body --max-time 60 -X POST "https://api.fortrip.ai/v1/orders/ord_Wr4tY7uI0oPa3SdF6gHj/pay" \
  -H "Authorization: Bearer $FORTRIP_TOKEN" \
  -H "Content-Type: application/json" \
  --data @- <<'JSON'
{
  "method": "alipay_wechat_pay",
  "total": {
    "amount": "132.40",
    "currency": "USD"
  }
}
JSON

List orders

#!/usr/bin/env bash
# List your orders, newest first.
# Needs FORTRIP_TOKEN, a Fortrip access token (see device-login).
set -euo pipefail

curl -sS --fail-with-body --max-time 60 "https://api.fortrip.ai/v1/orders?limit=10" \
  -H "Authorization: Bearer $FORTRIP_TOKEN"

Cancel

Cancel only while the order's cancel.available is true, with maximumPenalty the number in cancel.penalty.amount that the user agreed to.

#!/usr/bin/env bash
# Cancel an order under its terms, accepting no penalty.
# Needs FORTRIP_TOKEN, a Fortrip access token (see device-login).
set -euo pipefail

curl -sS --fail-with-body --max-time 60 -X POST "https://api.fortrip.ai/v1/orders/ord_Wr4tY7uI0oPa3SdF6gHj/cancel" \
  -H "Authorization: Bearer $FORTRIP_TOKEN" \
  -H "Content-Type: application/json" \
  --data @- <<'JSON'
{
  "maximumPenalty": 0
}
JSON

On this page