PréversionREST et JSON, contrat prévu
API de transferts aéroport pour agences de voyages et OTA
Devis, réservation, suivi et annulation de transferts aéroport via une seule API REST, avec chaque prix dans la devise de votre agence. L’API est en préversion : elle n’est pas encore ouverte aux clés API, et cette page présente le contrat prévu. Dites à l’équipe API ce que vous comptez construire.
La documentation est rédigée en anglais.
- Statut
- Préversion, pas encore ouverte aux clés API
- Contrat
- 8 endpoints prévus
- Prix
- Dans la devise de votre agence
- Exemples de code
- 9 langages
Voir un transfert réservé, appel par appel
La console rejoue les requêtes prévues dans une fenêtre de client API. Choisissez un scénario, regardez chaque requête se construire et partir, puis lisez la réponse. Rien sur cette page n’appelle un service : chaque requête et chaque réponse est une donnée d’exemple simulée, et la console ne joue que la sandbox.
3 requêtes : Trouver l’aéroport, Demander des devis, Réserver un devis.
Préversion : ce contrat n’est pas encore en production. Session illustrative : les corps de requête et de réponse sont des exemples tirés de la documentation, les dates sont décalées pour rester postérieures à aujourd’hui et les durées sont indicatives. Cette page n’envoie aucune requête.
Demander un devis et réserver un transfert aéroport
Préversion
Trouvez l’aéroport d’arrivée, demandez des devis et réservez-en un. La demande de devis renvoie un identifiant de devis pour chaque véhicule, et la réservation l’utilise.
Trouver l’aéroport
Saisissez au moins trois caractères et l’endpoint suggère des aéroports, chacun avec son code IATA. Une demande de devis désigne l’aéroport par ce code.
Requête GET /transfers/locations curl 'https://api.fx-port.com/api/v1/transfers/locations?query=ams&types=airport&limit=5' \ -H "Authorization: Bearer fxp_test_YOUR_KEY"Réponse 200 OK · 140 ms · 272 B 200 OK Content-Type: application/json Cache-Control: private, no-store X-Environment: sandbox { "environment": "sandbox", "success": true, "data": { "locations": [ { "location_id": "apt:AMS", "type": "airport", "iata_code": "AMS", "place_id": null, "name": "Amsterdam Airport Schiphol", "description": null, "city": "Amsterdam", "country_code": "NL", "latitude": 52.3105, "longitude": 4.7683 } ] } }- PASS Le code de statut est 200
- PASS $.data.locations[0].iata_code est égal à AMS
- PASS $.data.locations[0].location_id existe
Demander des devis
Envoyez le lieu de prise en charge, la destination, l’heure locale de prise en charge et les passagers. La réponse contient un devis par véhicule, chacun avec son identifiant de devis, son prix dans la devise de votre agence et une expiration.
Requête POST /transfers/quotes curl https://api.fx-port.com/api/v1/transfers/quotes \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "pickup": { "type": "airport", "iata_code": "AMS" }, "dropoff": { "type": "point", "latitude": 52.3676, "longitude": 4.9041, "name": "Amsterdam City Centre" }, "pickup_datetime": "2027-06-23T14:30", "passengers": { "adults": 2, "children": 0, "infants": 0 } }'Réponse 200 OK · 820 ms · 655 B 200 OK Content-Type: application/json Cache-Control: private, no-store X-Environment: sandbox { "environment": "sandbox", "success": true, "data": { "search_id": "tsr_01JC5T9ZK4Y2Q8M3V7N6B1A0XD", "distance_km": 20, "currency": "DZD", "expires_at": "2026-11-09T10:13:12Z", "quotes": [ { "quote_id": "tq_01JC5T9ZK4Y2Q8M3V7N6B1A0XE", "vehicle": { "make": "Toyota", "model": "Corolla", "type": "Sedan", "image_url": null, "max_passengers": 4, "suitcases": 2, "small_bags": 2 }, "operator": { "name": "Sandbox Transfers" }, "price": { "currency": "DZD", "total_price": 17823.33, "b2b_price": 17823.33, "agency_commission": 0 }, "extras": [], "cancellation": { "free_cancellation": true, "hours_before_pickup": 24, "source": "platform_default" }, "expires_at": "2026-11-09T10:13:12Z" } ], "meta": { "no_availability": false } } }- PASS Le code de statut est 200
- PASS $.data.quotes contient 1 élément
- PASS $.data.currency est égal à DZD
Réserver un devis
Envoyez l’identifiant de devis avec le passager principal et le numéro de vol. La réservation démarre en attente pendant que le fournisseur la confirme. Elle exige une clé Lecture + écriture.
Requête POST /transfers/bookings curl https://api.fx-port.com/api/v1/transfers/bookings \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "quote_id": "tq_01JC5T9ZK4Y2Q8M3V7N6B1A0XE", "passenger": { "first_name": "Jane", "last_name": "Doe", "email": "[email protected]", "phone": "+31612345678" }, "flight_number": "KL1234", "notes": "Arrival terminal 2", "luggage": { "suitcases": 1, "small_bags": 0 } }'Réponse 200 OK · 760 ms · 1.3 KB 200 OK Content-Type: application/json Cache-Control: private, no-store X-Environment: sandbox { "environment": "sandbox", "success": true, "data": { "idempotent_replay": false, "booking": { "id": "5b5b0e1c-6f7a-4c2d-9a53-0d2d4a0f9c11", "booking_id": "SBX-0000000001-AAB", "reference": "FXT-5B5B0E1C6F7A", "status": "pending", "state_detail": "awaiting_supplier_approval", "supplier_status": "PENDING_APPROVAL", "environment": "sandbox", "simulated": true, "pickup": { "type": "airport", "name": "Amsterdam Airport Schiphol", "iata_code": "AMS" }, "dropoff": { "type": "point", "name": "Amsterdam City Centre", "latitude": 52.3676, "longitude": 4.9041 }, "pickup_datetime": "2027-06-23T14:30", "flight_number": "KL1234", "notes": "Arrival terminal 2", "passengers": { "adults": 2, "children": 0, "infants": 0 }, "lead_passenger": { "first_name": "Jane", "last_name": "Doe", "email": "[email protected]", "phone": "+31612345678" }, "luggage": { "suitcases": 1, "small_bags": 0 }, "vehicle": { "make": "Toyota", "model": "Corolla", "type": "Sedan", "image_url": null, "max_passengers": 4 }, "operator": { "name": "Sandbox Transfers" }, "driver": null, "price": { "currency": "DZD", "total_price": 17823.33, "b2b_price": 17823.33, "agency_commission": 0 }, "refund": null, "documents": { "receipt_url": null, "voucher_url": null }, "is_cancelable": true, "can_cancel": true, "trip_group_id": null, "quote_id": "tq_01JC5T9ZK4Y2Q8M3V7N6B1A0XE", "status_updated_at": "2026-11-09T10:02:05Z", "created_at": "2026-11-09T10:02:05Z", "warnings": [] } } }- PASS Le code de statut est 200
- PASS $.data.booking.status est égal à pending
- PASS $.data.booking.simulated est égal à true
- PASS $.data.booking.reference existe
Suivre une réservation jusqu’à sa confirmation
Préversion
Lisez une nouvelle réservation, relisez-la plus tard et annulez-la. Chaque réponse indique quand redemander est utile, et la sandbox confirme la réservation après une courte attente.
Lire une nouvelle réservation
Une nouvelle réservation est en attente et n’a pas encore de chauffeur. La réponse indique au bout de combien de secondes redemander est utile.
Requête GET /transfers/bookings/{booking_id} curl https://api.fx-port.com/api/v1/transfers/bookings/5b5b0e1c-6f7a-4c2d-9a53-0d2d4a0f9c11 \ -H "Authorization: Bearer fxp_test_YOUR_KEY"Réponse 200 OK · 190 ms · 1.4 KB 200 OK { "environment": "sandbox", "success": true, "data": { "booking": { "id": "5b5b0e1c-6f7a-4c2d-9a53-0d2d4a0f9c11", "booking_id": "SBX-0000000001-AAB", "reference": "FXT-5B5B0E1C6F7A", "status": "pending", "state_detail": "awaiting_supplier_approval", "supplier_status": "PENDING_APPROVAL", "environment": "sandbox", "simulated": true, // ... 2 more "pickup_datetime": "2027-06-23T14:30", "flight_number": "KL1234", "notes": "Arrival terminal 2", // ... 16 more } }, "meta": { "next_poll_after_seconds": 120 } }- PASS Le code de statut est 200
- PASS $.data.booking.status est égal à pending
- PASS $.meta.next_poll_after_seconds est égal à 120
La relire plus tard
Un peu plus tard, la même lecture montre la réservation confirmée, avec un chauffeur dès qu’il est attribué.
Requête GET /transfers/bookings/{booking_id} curl https://api.fx-port.com/api/v1/transfers/bookings/5b5b0e1c-6f7a-4c2d-9a53-0d2d4a0f9c11 \ -H "Authorization: Bearer fxp_test_YOUR_KEY"Réponse 200 OK · 170 ms · 1.6 KB 200 OK { "environment": "sandbox", "success": true, "data": { "booking": { "id": "5b5b0e1c-6f7a-4c2d-9a53-0d2d4a0f9c11", "booking_id": "SBX-0000000001-AAB", "reference": "FXT-5B5B0E1C6F7A", "status": "confirmed", "state_detail": "confirmed", "supplier_status": "APPROVED", "environment": "sandbox", // ... 11 more "driver": { "name": "Simulated Driver", // ... 4 more }, // ... 10 more } }, "meta": { "next_poll_after_seconds": 21600 } }- PASS Le code de statut est 200
- PASS $.data.booking.status est égal à confirmed
- PASS $.data.booking.driver.name existe
- PASS $.meta.next_poll_after_seconds est égal à 21600
Annuler avec un motif
Annulez avec l’identifiant d’un motif. La sandbox répond avec la réservation remboursée, et aucun argent ne bouge puisque rien n’a été débité.
Requête POST /transfers/bookings/{booking_id}/cancel curl https://api.fx-port.com/api/v1/transfers/bookings/5b5b0e1c-6f7a-4c2d-9a53-0d2d4a0f9c11/cancel \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "reason_id": 6, "note": "customer request" }'Réponse 200 OK · 520 ms · 1.4 KB 200 OK { "environment": "sandbox", "success": true, "data": { "booking": { "id": "5b5b0e1c-6f7a-4c2d-9a53-0d2d4a0f9c11", "booking_id": "SBX-0000000001-AAB", "reference": "FXT-5B5B0E1C6F7A", "status": "refunded", "state_detail": "completed", "supplier_status": "REFUNDED", "environment": "sandbox", "simulated": true, // ... 2 more "pickup_datetime": "2027-06-23T14:30", "flight_number": "KL1234", // ... 17 more }, "refund": { // ... 4 more "status": "not_applicable" } } }- PASS Le code de statut est 200
- PASS $.data.booking.status est égal à refunded
- PASS $.data.refund.status est égal à not_applicable
Gérer un prix qui a bougé
Préversion
Un numéro de vol PRICEUP fait augmenter le prix par la sandbox entre le devis et la réservation. L’API refuse de réserver au prix plus élevé tant que vous n’avez pas demandé un nouveau devis.
Demander un devis
Le devis conserve un prix pour le trajet. Gardez son identifiant de devis et son total.
Requête POST /transfers/quotes curl https://api.fx-port.com/api/v1/transfers/quotes \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "pickup": { "type": "airport", "iata_code": "AMS" }, "dropoff": { "type": "point", "latitude": 52.3676, "longitude": 4.9041, "name": "Amsterdam City Centre" }, "pickup_datetime": "2027-06-23T14:30", "passengers": { "adults": 2, "children": 0, "infants": 0 } }'Réponse 200 OK · 820 ms · 655 B 200 OK { "environment": "sandbox", "success": true, "data": { "search_id": "tsr_01JC5T9ZK4Y2Q8M3V7N6B1A0XD", "distance_km": 20, "currency": "DZD", "expires_at": "2026-11-09T10:13:12Z", "quotes": [ { "quote_id": "tq_01JC5T9ZK4Y2Q8M3V7N6B1A0XE", // ... 2 more "price": { "currency": "DZD", "total_price": 17823.33, // ... 2 more }, "extras": [], // ... 2 more } ], // ... 1 more } }- PASS Le code de statut est 200
- PASS $.data.quotes[0].price.total_price est égal à 17823.33
Réserver, et le prix a bougé
La sandbox augmente le prix quand le numéro de vol est
PRICEUP. L’API répond409avecprice_changed, le total précédent et le total actuel. Rien n’est réservé.Requête POST /transfers/bookings curl https://api.fx-port.com/api/v1/transfers/bookings \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "quote_id": "tq_01JC5T9ZK4Y2Q8M3V7N6B1A0XE", "passenger": { "first_name": "Jane", "last_name": "Doe", "email": "[email protected]", "phone": "+31612345678" }, "flight_number": "PRICEUP", "notes": "Arrival terminal 2", "luggage": { "suitcases": 1, "small_bags": 0 } }'Réponse 409 Conflict · 410 ms · 482 B 409 Conflict { "environment": "sandbox", "success": false, "errors": [ { "code": "price_changed", "type": "conflict", "title": "Price changed", "message": "The price changed since the quote was issued. Request a new quote and confirm the new price.", "field": null, "details": { "previous_total_price": 17823.33, "current_total_price": 18715.1, "currency": "DZD" }, "documentation_url": "https://fx-port.com/docs/errors#price_changed" } ], "meta": { "request_id": "req_3c1f9a7be204", "status": 409 }, "request_id": "req_3c1f9a7be204" }- PASS Le code de statut est 409
- PASS Le code d’erreur est price_changed
- PASS $.errors[0].details.previous_total_price est égal à 17823.33
- PASS $.errors[0].details.current_total_price est égal à 18715.1
Demander un nouveau devis
Demandez à nouveau un devis pour le même trajet. Le nouveau devis a un nouvel identifiant et le prix plus élevé, que le voyageur peut maintenant accepter ou refuser.
Requête POST /transfers/quotes curl https://api.fx-port.com/api/v1/transfers/quotes \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "pickup": { "type": "airport", "iata_code": "AMS" }, "dropoff": { "type": "point", "latitude": 52.3676, "longitude": 4.9041, "name": "Amsterdam City Centre" }, "pickup_datetime": "2027-06-23T14:30", "passengers": { "adults": 2, "children": 0, "infants": 0 } }'Réponse 200 OK · 790 ms · 653 B 200 OK { "environment": "sandbox", "success": true, "data": { "search_id": "tsr_01JC5TA2M7R9W4X6Z8B3C5D7F1", "distance_km": 20, "currency": "DZD", "expires_at": "2026-11-09T10:15:31Z", "quotes": [ { "quote_id": "tq_01JC5TA2M7R9W4X6Z8B3C5D7F2", // ... 2 more "price": { "currency": "DZD", "total_price": 18715.1, // ... 2 more }, "extras": [], // ... 2 more } ], // ... 1 more } }- PASS Le code de statut est 200
- PASS $.data.quotes[0].price.total_price est égal à 18715.1
Réserver le nouveau devis
Réservez avec le nouvel identifiant de devis. Le prix correspond désormais, et la réservation est effectuée.
Requête POST /transfers/bookings curl https://api.fx-port.com/api/v1/transfers/bookings \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "quote_id": "tq_01JC5TA2M7R9W4X6Z8B3C5D7F2", "passenger": { "first_name": "Jane", "last_name": "Doe", "email": "[email protected]", "phone": "+31612345678" }, "flight_number": "PRICEUP", "notes": "Arrival terminal 2", "luggage": { "suitcases": 1, "small_bags": 0 } }'Réponse 200 OK · 740 ms · 1.3 KB 200 OK { "environment": "sandbox", "success": true, "data": { "idempotent_replay": false, "booking": { "id": "5b5b0e1c-6f7a-4c2d-9a53-0d2d4a0f9c11", "booking_id": "SBX-0000000001-AAB", "reference": "FXT-5B5B0E1C6F7A", "status": "pending", "state_detail": "awaiting_supplier_approval", "supplier_status": "PENDING_APPROVAL", "environment": "sandbox", "simulated": true, // ... 2 more "pickup_datetime": "2027-06-23T14:30", "flight_number": "PRICEUP", "notes": "Arrival terminal 2", // ... 5 more "driver": null, // ... 10 more } } }- PASS Le code de statut est 200
- PASS $.data.booking.status est égal à pending
- PASS $.data.booking.price.total_price est égal à 18715.1
Se remettre d’une réponse perdue
Préversion
Un nom de famille Timeout fait perdre à la sandbox la réponse à une réservation. Vous vous en remettez en lisant la réservation, jamais en réservant à nouveau.
La réponse est perdue
La sandbox perd la réponse quand le nom de famille est
Timeout. L’API répond202: la réservation est en attente, son état estreconciling, et le message dit de ne pas réserver à nouveau.Requête POST /transfers/bookings curl https://api.fx-port.com/api/v1/transfers/bookings \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "quote_id": "tq_01JC5T9ZK4Y2Q8M3V7N6B1A0XE", "passenger": { "first_name": "Jane", "last_name": "Timeout", "email": "[email protected]", "phone": "+31612345678" }, "flight_number": "KL1234", "notes": "Arrival terminal 2", "luggage": { "suitcases": 1, "small_bags": 0 } }'Réponse 202 Accepted · 880 ms · 441 B 202 Accepted { "environment": "sandbox", "success": true, "data": { "booking": { "id": "5b5b0e1c-6f7a-4c2d-9a53-0d2d4a0f9c11", "booking_id": null, "reference": "FXT-5B5B0E1C6F7A", "status": "pending", "state_detail": "reconciling", "quote_id": "tq_01JC5T9ZK4Y2Q8M3V7N6B1A0XE" }, "message": "We could not confirm this booking with the transport network yet. Your balance is reserved. Do not book again; poll GET /api/v1/transfers/bookings/5b5b0e1c-6f7a-4c2d-9a53-0d2d4a0f9c11" } }- PASS Le code de statut est 202
- PASS $.data.booking.state_detail est égal à reconciling
- PASS $.data.booking.booking_id est égal à null
Retrouver la réservation
Listez les réservations en filtrant sur l’identifiant de devis. La liste renvoie la réservation à laquelle appartenait la réponse perdue : il n’y a donc aucune raison de réserver à nouveau.
Requête GET /transfers/bookings curl 'https://api.fx-port.com/api/v1/transfers/bookings?quote_id=tq_01JC5T9ZK4Y2Q8M3V7N6B1A0XE' \ -H "Authorization: Bearer fxp_test_YOUR_KEY"Réponse 200 OK · 230 ms · 1.3 KB 200 OK { "environment": "sandbox", "success": true, "data": { "bookings": [ { "id": "5b5b0e1c-6f7a-4c2d-9a53-0d2d4a0f9c11", "booking_id": null, "reference": "FXT-5B5B0E1C6F7A", // ... 25 more } ] }, "pagination": { "page": 1, "limit": 50, "total": 1, "total_pages": 1, "has_more": false }, "meta": { "as_of": "2026-11-09T10:03:40Z" } }- PASS Le code de statut est 200
- PASS $.pagination.total est égal à 1
- PASS $.data.bookings[0].state_detail est égal à reconciling
Réserver à nouveau trop tôt
Envoyer la même réservation alors que la première est encore en cours est refusé avec
409etbooking_in_progress, accompagnés d’un en-têteRetry-After. Lisez plutôt la réservation.Requête POST /transfers/bookings curl https://api.fx-port.com/api/v1/transfers/bookings \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "quote_id": "tq_01JC5T9ZK4Y2Q8M3V7N6B1A0XE", "passenger": { "first_name": "Jane", "last_name": "Timeout", "email": "[email protected]", "phone": "+31612345678" }, "flight_number": "KL1234", "notes": "Arrival terminal 2", "luggage": { "suitcases": 1, "small_bags": 0 } }'Réponse 409 Conflict · 150 ms · 423 B 409 Conflict Retry-After: 3 { "environment": "sandbox", "success": false, "errors": [ { "code": "booking_in_progress", "type": "conflict", "title": "Booking in progress", "message": "This quote is already being booked. Wait a few seconds, then read the booking.", "field": null, "details": { "retry_after": 3 }, "documentation_url": "https://fx-port.com/docs/errors#booking_in_progress" } ], "meta": { "request_id": "req_8a47d05e91bc", "status": 409 }, "request_id": "req_8a47d05e91bc" }- PASS Le code de statut est 409
- PASS Le code d’erreur est booking_in_progress
- PASS L’en-tête Retry-After est présent
Annuler, et ce qui bloque une annulation
Préversion
Lisez les motifs d’annulation, faites une réservation avec un numéro de vol NOCANCEL et regardez l’API refuser de l’annuler.
Lister les motifs
Les motifs arrivent sous forme de liste d’identifiants et de noms. Vous envoyez l’identifiant de l’un d’eux avec l’appel d’annulation.
Requête GET /transfers/cancellation-reasons curl https://api.fx-port.com/api/v1/transfers/cancellation-reasons \ -H "Authorization: Bearer fxp_test_YOUR_KEY"Réponse 200 OK · 120 ms · 487 B 200 OK { "environment": "sandbox", "success": true, "data": { "source": "supplier", "reasons": [ { "id": 1, "name": "Flight cancelled", // ... 2 more }, { // ... 4 more }, { // ... 4 more }, { // ... 4 more }, // ... 2 more ] } }- PASS Le code de statut est 200
- PASS $.data.reasons contient 6 éléments
- PASS $.data.reasons[5].name est égal à Other
Faire la réservation
La sandbox crée une réservation impossible à annuler quand le numéro de vol est
NOCANCEL. La réservation l’indique dans son champcan_cancel.Requête POST /transfers/bookings curl https://api.fx-port.com/api/v1/transfers/bookings \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "quote_id": "tq_01JC5T9ZK4Y2Q8M3V7N6B1A0XE", "passenger": { "first_name": "Jane", "last_name": "Doe", "email": "[email protected]", "phone": "+31612345678" }, "flight_number": "NOCANCEL", "notes": "Arrival terminal 2", "luggage": { "suitcases": 1, "small_bags": 0 } }'Réponse 200 OK · 770 ms · 1.3 KB 200 OK { "environment": "sandbox", "success": true, "data": { "idempotent_replay": false, "booking": { "id": "5b5b0e1c-6f7a-4c2d-9a53-0d2d4a0f9c11", "booking_id": "SBX-0000000001-AAB", "reference": "FXT-5B5B0E1C6F7A", "status": "pending", "state_detail": "awaiting_supplier_approval", "supplier_status": "PENDING_APPROVAL", "environment": "sandbox", "simulated": true, // ... 2 more "pickup_datetime": "2027-06-23T14:30", "flight_number": "NOCANCEL", "notes": "Arrival terminal 2", // ... 10 more "can_cancel": false, // ... 5 more } } }- PASS Le code de statut est 200
- PASS $.data.booking.can_cancel est égal à false
- PASS $.data.booking.is_cancelable est égal à false
Essayer de l’annuler
L’annulation est refusée avec
409etcancellation_not_allowed, et les détails donnent la raison. Une réservation qui peut être annulée répond avec son remboursement.Requête POST /transfers/bookings/{booking_id}/cancel curl https://api.fx-port.com/api/v1/transfers/bookings/5b5b0e1c-6f7a-4c2d-9a53-0d2d4a0f9c11/cancel \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "reason_id": 6, "note": "customer request" }'Réponse 409 Conflict · 260 ms · 403 B 409 Conflict { "environment": "sandbox", "success": false, "errors": [ { "code": "cancellation_not_allowed", "type": "conflict", "title": "Cancellation not allowed", "message": "This booking cannot be cancelled.", "field": null, "details": { "reason": "not_cancelable" }, "documentation_url": "https://fx-port.com/docs/errors#cancellation_not_allowed" } ], "meta": { "request_id": "req_d2e60b3f7a18", "status": 409 }, "request_id": "req_d2e60b3f7a18" }- PASS Le code de statut est 409
- PASS Le code d’erreur est cancellation_not_allowed
- PASS $.errors[0].details.reason est égal à not_cancelable
Les montants, identifiants, noms, dates et durées de ces exemples sont donnés à titre d’illustration, et l’opérateur qui y figure est un opérateur de sandbox fictif.
Endpoints prévus et clé requise pour chacun
L’API Transferts prévue compte 8 endpoints. Ils sont en préversion : aucun ne renvoie encore vers une page de référence.
| Endpoint | Fonction | Clé |
|---|---|---|
GET /api/v1/transfers/locationsPréversion | Suggérer des aéroports pendant la saisie, chacun avec son code IATA, sa ville, son pays et ses coordonnées. | Lecture |
POST /api/v1/transfers/quotesPréversion | Tarifer un transfert aller simple pour votre agence : un devis par véhicule, chacun avec son identifiant de devis et son expiration. | Lecture |
GET /api/v1/transfers/quotes/{quote_id}Préversion | Relire un devis conservé : son prix, son expiration et son état. | Lecture |
POST /api/v1/transfers/bookingsPréversion | Réserver un devis. La réservation démarre en général en attente jusqu’à confirmation du fournisseur. | Lecture + écriture |
GET /api/v1/transfers/bookingsPréversion | Lister vos réservations, filtrées par statut, dates, devis ou groupe de trajets, en pages stables. | Lecture |
GET /api/v1/transfers/bookings/{booking_id}Préversion | Lire une réservation par son identifiant, sa référence ou son numéro de réservation : statut, chauffeur, documents et moment où redemander. | Lecture |
POST /api/v1/transfers/bookings/{booking_id}/cancelPréversion | Annuler une réservation avec un motif. La réponse indique si le remboursement est fait ou encore en attente. | Lecture + écriture |
GET /api/v1/transfers/cancellation-reasonsPréversion | Lister les motifs que vous pouvez donner pour annuler une réservation. | Lecture |
Tous les endpoints prévus se trouvent sous l’URL de base que partagent toutes les API FX-Port, https://api.fx-port.com/api/v1, dans un chemin qui commence par /transfers.
Demander un devis
Une demande de devis indique le lieu de prise en charge, la destination, l’heure de prise en charge et les passagers. L’une des extrémités doit être un aéroport, donné par son code IATA à trois lettres. Donnez l’heure de prise en charge en heure locale du lieu de départ, sans fuseau horaire : une heure avec décalage ou avec
Zest refusée. Les bébés comptent dans la capacité du véhicule.Faire une réservation
Une réservation prend un seul
quote_id, le nom, l’e-mail et le numéro de téléphone du passager principal au format international, ainsi que le numéro de vol. Vous pouvez ajouter des notes, le nombre de bagages, votre propre référence et un groupe de trajets. Le prix vient toujours du devis : un prix indiqué dans la requête est ignoré.
Comme les autres API FX-Port, la clé se place dans l’en-tête Authorization sous forme de jeton Bearer. Une clé Lecture peut consulter les lieux, demander des devis et lire les réservations et les motifs d’annulation. Faire une réservation ou en annuler une exige une clé Lecture + écriture. Les limites de débit des transferts ne sont pas encore publiées.
Conçu pour éviter qu’un transfert soit réservé deux fois
L’argent est engagé à la réservation : le contrat prévu est donc construit autour des cas qui tournent mal, à savoir une réponse perdue, un prix qui a bougé et une nouvelle tentative. Trois règles les couvrent.
Un devis, une réservation
Chaque devis a son propre
quote_id, et le serveur conserve son prix pendant 15 minutes. Une réservation utilise exactement un devis, et c’est ce devis qui empêche de réserver deux fois : il n’y a donc pas de clé d’idempotence. Une fois le premier appel de réservation terminé, renvoyer la même réservation retourne la réservation enregistrée, marquéeidempotent_replay. Envoyer un corps différent pour le même devis est refusé.Une réponse peu claire n’est pas une raison de réserver à nouveau
Quand le fournisseur ne confirme pas à temps, l’API répond
202avec la réservation en attente et son état àreconciling. Considérez qu’une réservation existe peut-être. Ne réservez pas à nouveau : lisez la réservation en filtrant sur l’identifiant de devis, puis interrogez-la jusqu’à ce qu’elle soit confirmée ou échouée. Il en va de même pour une requête qui expire de votre côté.Un prix qui a bougé est signalé, pas facturé
Juste avant la réservation, le prix est revérifié auprès du fournisseur. S’il a augmenté depuis le devis, rien n’est réservé et l’API répond
409avecprice_changed, le total précédent et le total actuel. Montrez le nouveau prix au voyageur, demandez un nouveau devis et réservez celui-ci.
| Réponse | Signification | Que faire |
|---|---|---|
200 idempotent_replay | Le même devis et le même corps ont déjà été réservés. | Utilisez la réservation renvoyée. Rien de nouveau n’a été créé. |
202 booking_pending_confirmation | Le résultat est incertain et le montant est bloqué sur le solde. | Ne réservez jamais à nouveau. Lisez la réservation par identifiant de devis, puis interrogez-la. |
409 booking_in_progress | Le même devis est encore en cours de réservation. | Attendez le délai indiqué dans l’en-tête Retry-After, puis lisez la réservation. |
409 duplicate_booking | Le devis a déjà été réservé avec d’autres informations. | Ne réessayez pas. Lisez la réservation existante. |
409 price_changed | Le prix a augmenté depuis le devis. | Montrez le nouveau prix, demandez un nouveau devis et réservez celui-ci. |
409 quote_expired, vehicle_unavailable | Le devis est inconnu, expiré ou déjà utilisé, ou son véhicule n’est plus proposé. | Demandez un nouveau devis. |
503 supplier_busy | Le fournisseur est occupé. Rien n’a été réservé. | Renvoyez la même requête après le délai Retry-After. |
402 insufficient_balance | Le solde de l’agence ne couvre pas la réservation. | Alimentez le solde, puis réservez à nouveau. |
Testez chaque cas dans la sandbox
La sandbox prévue est un simulateur. Ce que vous envoyez détermine ce qui se passe : chaque cas d’une réservation peut donc être testé sans vrai fournisseur et sans mouvement d’argent.
Reconnaître une réservation de sandbox
Une réservation de sandbox est marquée
simulatedet possède un numéro de réservation qui commence parSBX-. Aucun solde n’est débité et rien n’est envoyé à un vrai fournisseur.Aéroports et véhicules
La sandbox connaît un ensemble fixe de 25 aéroports. Un aéroport hors de cet ensemble est refusé comme code d’aéroport invalide. Les véhicules, les opérateurs et les prix sont des données d’exemple. Une prise en charge très proche de l’instant présent ne renvoie aucun devis, et une prise en charge un peu plus tardive renvoie moins de véhicules.
| Champ | Valeur | Ce qui se passe |
|---|---|---|
passenger.last_name | Pending | La réservation reste en attente longtemps, ce qui permet de tester l’annulation d’une réservation en attente et un polling plus long. |
passenger.last_name | Declined | L’opérateur refuse peu après la réservation, et la réservation se termine en échec. |
passenger.last_name | Rejected | La réservation est refusée immédiatement avec 422 et supplier_rejected. |
passenger.last_name | Timeout | La réponse à la réservation est perdue : 202 avec l’état reconciling. La réservation se confirme d’elle-même un peu plus tard. |
passenger.last_name | Cancelled | L’opérateur annule peu après la réservation, et la réservation se termine annulée. |
flight_number | NOCANCEL | La réservation ne peut pas être annulée : un appel d’annulation répond 409 avec cancellation_not_allowed. |
flight_number | PRICEUP | Le prix augmente entre le devis et la réservation : 409 avec price_changed. |
notes | [sim:slow] | L’appel de réservation reçoit une réponse lente, ce qui permet de tester le délai d’expiration de votre client. |
notes | [sim:busy] | L’appel de réservation échoue avec 503 et supplier_busy, accompagné d’un en-tête Retry-After, ce qui permet de tester le backoff. |
Pas de webhooks : interrogez la réservation pour la suivre
Dans le contrat prévu, FX-Port n’appelle aucune de vos URL lorsqu’une réservation change. Vous lisez la réservation, et chaque réponse indique à quel moment il est utile de redemander.
Redemandez quand la réponse le dit
Chaque lecture d’une réservation contient meta.next_poll_after_seconds, le nombre de secondes au bout duquel redemander est utile, ou null une fois la réservation terminée. Redemander plus tôt ne fait que répéter la réponse.
| Quand | Attente |
|---|---|
| Tant que la réservation est en attente, quelle que soit l’heure de prise en charge | 120 |
| La prise en charge a lieu dans moins de 48 heures | 900 |
| La prise en charge a lieu entre 48 heures et une semaine | 3600 |
| La prise en charge a lieu dans plus d’une semaine | 21600 |
| La réservation est terminée : arrêtez l’interrogation | null |
| Statut | Détail | Signification |
|---|---|---|
pending | awaiting_supplier_approval | La réservation existe, mais le fournisseur ne l’a pas encore approuvée. Elle peut encore être annulée. |
pending | reconciling | Le résultat est incertain et le montant est bloqué sur le solde. La réservation ne peut pas encore être annulée, et vous ne devez pas réserver à nouveau. |
confirmed | confirmed | Le fournisseur a approuvé la réservation. Un chauffeur n’est peut-être pas encore attribué. |
confirmed | completed | Le trajet est terminé. Vous pouvez arrêter l’interrogation. |
cancelled | refund_pending | Annulée auprès du fournisseur, mais le solde n’a pas encore été recrédité. |
refunded | completed | Annulée et intégralement recréditée. |
partial_refund | completed | Annulée, et une partie du montant a été recréditée. |
failed | declined, failed | La réservation n’a jamais été confirmée, et le montant bloqué a été restitué. |
Chauffeur et documents
Le bloc chauffeur reste vide tant que l’opérateur n’a pas attribué de chauffeur : continuez donc à interroger à mesure que la prise en charge approche. Dès qu’il y a un chauffeur, le bloc contient son nom, son numéro de téléphone ainsi que la plaque et la marque du véhicule. Un lien vers le reçu apparaît peu après la réservation, et un lien vers le bon de transfert dès qu’un chauffeur est attribué.
Interroger le fournisseur maintenant
Ajoutez
refresh=truepour lire le statut auprès du fournisseur plutôt que dans l’enregistrement propre à FX-Port. C’est autorisé une fois par réservation toutes les 30 secondes.Les lectures sont limitées à votre agence
Lisez une réservation par son identifiant, par sa référence
FXT-ou par son numéro de réservation. La réservation d’une autre agence renvoie le même404qu’une réservation inconnue. Pour lister les réservations, filtrez par statut, dates, devis ou groupe de trajets, et renvoyezmeta.as_ofsous la formeas_ofsur les pages suivantes pour que les nouvelles réservations ne les décalent pas.
Ce que l’API Transferts ne fait pas
Connaître les limites tôt fait gagner du temps d’intégration. Voici les bornes du contrat prévu.
Un sens par devis
Un devis couvre un seul trajet. Pour un aller-retour, demandez deux devis et faites deux réservations, puis liez-les avec un
trip_group_id.Un aéroport à une extrémité
Chaque transfert commence ou se termine dans un aéroport. Un trajet entre deux adresses est refusé : les transferts de ville à ville ne sont donc pas proposés.
Les options ne peuvent pas être réservées
Un devis peut lister des options à titre d’information. Envoyer des options avec une réservation est refusé avec
extras_not_supported.Pas d’endpoint pour modifier une réservation
Il n’existe aucun appel pour éditer une réservation. Pour en changer une, annulez-la et réservez à nouveau avec un nouveau devis.
Pas de webhooks
FX-Port n’appelle aucune de vos URL lorsqu’une réservation change. Interrogez plutôt la réservation.
Les lieux exigent des coordonnées
Une extrémité qui n’est pas un aéroport s’envoie comme un point : latitude, longitude et un nom. La recherche de lieux par nom n’est pas encore proposée.
Prix, commission et ce que paie votre solde
Dans le contrat prévu, chaque devis, réservation et annulation porte le même bloc de prix, dans la devise du solde de votre agence.
| Champ | Signification |
|---|---|
currency | La devise du solde de votre agence. |
total_price | Ce que paie le voyageur. |
b2b_price | Ce qui est débité du solde de votre agence à la réservation. |
agency_commission | La commission que votre agence gagne sur la réservation. |
Comment les champs s’additionnent
total_priceest égal àb2b_priceplusagency_commission, doncb2b_price = total_price - agency_commission. Les montants sont des nombres JSON à deux décimales, arrondis au centime supérieur.Ce qu’un prix ne montre pas
Le prix et la devise propres au fournisseur, les taux de change et les commissions internes de FX-Port n’apparaissent dans aucune réponse. Vous voyez ce que paie votre agence et ce que paie le voyageur.
Payé depuis le solde de votre agence
Une réservation est payée depuis le solde de l’agence. Quand le solde ne la couvre pas, l’API refuse la réservation avec
402etinsufficient_balance, et les détails de l’erreur donnent le solde dont vous disposez et le montant nécessaire.
Qui construit avec l’API Transferts
Les mêmes appels servent trois types d’équipes, et les règles sur l’argent et les nouvelles tentatives sont les mêmes pour toutes.
Back-offices d’agences de voyages
Les agents recherchent depuis l’aéroport d’arrivée, présentent les devis avec véhicule, capacité et prix, et réservent celui que choisit le voyageur. Les appels de base sont
GET /transfers/locations,POST /transfers/quotesetPOST /transfers/bookings.Agences de voyages en ligne et plateformes
Une OTA vend le transfert à côté du vol et de l’hôtel. Elle réserve avec le numéro de vol du billet qu’elle vient de vendre, liste ses réservations par statut et par période, et annule avec un motif. Un aller-retour correspond à deux réservations reliées par un groupe de trajets.
Outils de voyages d’affaires
Un outil de réservation pour entreprises ajoute le transfert d’arrivée lorsqu’un voyage est approuvé, enregistre sa propre référence sur la réservation et relit la réservation avant le voyage pour afficher le chauffeur.
Ce qui fonctionne aujourd’hui et ce qui est prévu ensuite
Tout ce que décrit cette page est un contrat prévu, à l’exception des deux lectures ci-dessous.
Transferts réservés dans le tableau de bord
Les lectures de l’historique des réservations et du détail d’une réservation acceptent déjà
product=transfers. Elles renvoient les transferts réservés dans le tableau de bord FX-Port, avec la date d’arrivée, le numéro de vol et les liens vers le bon de transfert et le reçu.Ce qui est prévu ensuite
Le projet est d’ouvrir les endpoints de transferts aux clés API, de proposer un simulateur de sandbox pour ces clés et de publier des pages de référence dans la documentation. Aucune date n’est fixée.
Ce qui n’est pas encore publié
Les chiffres de couverture, la liste des opérateurs, les limites de débit et les engagements de service ne sont pas encore publiés pour les transferts, et les montants des exemples sont des échantillons. Si l’un d’eux compte pour votre projet, demandez à l’équipe API.
API de transferts aéroport : questions fréquentes
Qu’est-ce que l’API de transferts aéroport FX-Port ?
C’est une API REST prévue qui permet à une agence de voyages ou à une OTA de demander des devis, de réserver, de suivre et d’annuler des transferts aéroport. Vous demandez des devis avec un lieu de prise en charge, une destination, une heure et les passagers, vous réservez l’un des devis que le serveur conserve pour vous, puis vous lisez la réservation jusqu’à sa confirmation. Requêtes et réponses sont en JSON, et les prix sont dans la devise de votre agence.
Puis-je utiliser l’API Transferts dès aujourd’hui ?
Pas encore. L’API Transferts est en préversion : ses endpoints ne sont pas ouverts aux clés API, et cette page décrit le contrat prévu. Les seuls appels de transferts qui fonctionnent aujourd’hui sont les lectures de l’historique des réservations, qui renvoient les transferts réservés dans le tableau de bord FX-Port. Dites à l’équipe API ce que vous comptez construire : elle pourra vous présenter ce qui est prévu.
Comment joindre l’équipe API, et que lui dire ?
Écrivez à l’équipe API à l’adresse [email protected]. Indiquez le type d’activité que vous exercez, les aéroports que vous desservez et ce que vous voulez réserver, par exemple des arrivées simples ou des allers-retours. Cela lui montre quelles parties du contrat comptent le plus pour vous. Vous pouvez aussi créer d’abord un compte FX-Port.
Quels aéroports et quels trajets puis-je tarifer ?
Chaque transfert a un aéroport à l’une de ses extrémités, donné par un code IATA. L’autre extrémité est un autre aéroport ou un point avec des coordonnées et un nom. Un devis couvre un seul sens : un aller-retour correspond donc à deux devis et deux réservations. FX-Port n’a pas encore publié de chiffres de couverture ni de liste d’opérateurs pour les transferts, et la sandbox connaît un ensemble fixe d’aéroports.
Dans quelle devise sont les prix, et que paie-t-on ?
Les prix sont dans la devise du solde de votre agence. Chaque prix indique le total que paie le voyageur, votre commission et le montant débité de votre solde, qui est le total moins votre commission. Les montants sont arrondis au centime supérieur, et le prix propre au fournisseur ainsi que les taux de change ne sont pas affichés.
Que faire si une demande de réservation expire ?
Ne la renvoyez pas. Une requête qui expire a peut-être abouti, et une réservation acceptée mais pas encore confirmée est renvoyée en attente. Lisez vos réservations filtrées par identifiant de devis : cela renvoie la réservation si elle existe. Interrogez-la ensuite jusqu’à ce qu’elle soit confirmée ou échouée. Réserver à nouveau avec un nouveau devis pourrait créer une seconde réservation.
Que se passe-t-il si le prix change avant ma réservation ?
Le prix est revérifié auprès du fournisseur juste avant la réservation. S’il a augmenté, rien n’est réservé et l’API répond avec le total précédent et le total actuel. Montrez le nouveau prix au voyageur, demandez un nouveau devis et réservez celui-ci. Un devis est conservé pendant 15 minutes : ne le gardez donc pas longtemps.
Puis-je modifier ou annuler une réservation ?
Il n’existe aucun appel pour éditer une réservation : annulez-la et réservez à nouveau. Une annulation prend un motif choisi dans une liste que fournit l’API. La réponse indique si le remboursement est fait ou encore en attente du fournisseur, et une réservation qui ne peut pas être annulée est refusée avec un motif. Un devis affiche une estimation du délai d’annulation et son origine : considérez-la comme une estimation.
FX-Port envoie-t-il des webhooks, et comment suivre une réservation ?
Non. FX-Port n’appelle aucune de vos URL. Lisez plutôt la réservation : chaque lecture indique combien de secondes attendre avant de redemander, et l’attente dépend du statut et de la proximité de la prise en charge. Une fois la réservation terminée, la réponse vous dit d’arrêter l’interrogation.
Existe-t-il une sandbox pour tester ?
Une sandbox est prévue sous forme de simulateur avec des valeurs de test réservées. Ces valeurs produisent une réservation en attente, une réservation refusée, une réponse perdue, un prix qui bouge et une réservation impossible à annuler : chaque cas peut donc être testé sans vrais opérateurs et sans mouvement d’argent. Chaque réservation de sandbox est marquée comme simulée. La sandbox n’est pas encore ouverte aux clés API.
API et pages associées
Un voyage ne se limite pas à un transfert. Les API Vols, Hôtels et eSIM partagent l’URL de base, le format de clé et le corps d’erreur autour desquels l’API Transferts est conçue : un seul client et un seul gestionnaire d’erreurs peuvent donc les servir toutes.
Recherchez, tarifez et réservez des vols, réglez les commandes mises en attente, annulez et consultez les billets.
Trouvez des hôtels, vérifiez les tarifs, préréservez et réservez, consultez les vouchers et annulez.
- eSIM APINouveau
Parcourez les forfaits eSIM, passez des commandes, rechargez, consultez la consommation et obtenez les instructions d’installation.
- Transferts aéroport dans le tableau de bord FX-Port
Vous préférez un écran à une API ? Le personnel de l’agence peut réserver des transferts aéroport dans le tableau de bord FX-Port, sans écrire de code.
- Comment réserver des transferts aéroport avec FX-Port
Un guide pas à pas pour réserver des transferts aéroport avec FX-Port.
- Documentation de l’API FX-Port
La documentation explique les clés, les erreurs et les limites de débit que partagent toutes les API FX-Port.
- llms.txt pour les outils d’IA
Dites à l’équipe API ce que vous comptez construire
Les transferts sont en préversion : l’étape suivante est donc une conversation. Indiquez le type d’activité que vous exercez, les aéroports que vous desservez et ce que vous voulez réserver. Vous pouvez aussi créer d’abord un compte FX-Port.