Pony for partners
Support technique ↗
Pony · API partenaires

Intégrez la flotte Pony à votre service

Quatre familles d'API selon ce que vous construisez : un flux public de disponibilité des véhicules (GBFS), un reporting réglementaire pour les villes (MDS & NeTEx), ou une intégration complète pour vendre le trajet dans votre propre app (MaaS).

Environnements

Chaque API existe en QA (bac à sable, flotte réduite) et en Production. Utilisez le sélecteur QA / Prod en haut de la page : tous les exemples de cette documentation basculent automatiquement sur le bon nom d'hôte.

API QA Production
GBFSgbfs-dev.getapony.comgbfs.getapony.com
MDS / NeTExmds-dev.getapony.commds.getapony.com
MaaSpartners-dev.getapony.compartners.getapony.com
i

La QA n'expose qu'une flotte réduite de véhicules de test. Validez votre intégration ici avant toute demande de passage en production.

Authentification

Le modèle d'authentification varie selon l'API :

API Méthode Portée
GBFSPublique, sans clé (feeds standards) — clé key optionnelle pour les champs étendus MaaSLecture seule
MDS / NeTExClé key en query param, une clé par ville/agenceLecture seule, restreinte GCP
MaaSapi_key + app_id en query paramLecture/écriture, scopée à votre app_id

Vos identifiants (clé GBFS, clé MDS, ou couple api_key/app_id MaaS) vous sont communiqués individuellement à l'onboarding — ils ne sont jamais partagés entre partenaires.

Pony Partner APIs Une question d'intégration ? partners-tech@getapony.com
Lecture seule · sans authentification

GBFS

Le General Bikeshare Feed Specification est le standard ouvert qui décrit la position, la disponibilité et la tarification d'une flotte de mobilité partagée. Pony expose les feeds GBFS 2.2 et 3.0, en libre accès, pour chaque région opérée.

Auto-discovery

Un seul appel gbfs.json retourne la liste des feeds disponibles pour une région. C'est le point d'entrée à consommer en premier — les URLs des feeds individuels ne doivent pas être codées en dur côté partenaire.

v2.2 — un feed par langue

GET https://gbfs-dev.getapony.com/v1/{region_id}/{language}/gbfs.jsonhttps://gbfs.getapony.com/v1/{region_id}/{language}/gbfs.json
curl "https://gbfs-dev.getapony.com/v1/paris/fr/gbfs.json"
curl "https://gbfs.getapony.com/v1/paris/fr/gbfs.json"

v3.0 — un feed unique, multilingue

GET https://gbfs-dev.getapony.com/v3/{region_id}/gbfs.jsonhttps://gbfs.getapony.com/v3/{region_id}/gbfs.json

region_id est l'identifiant de la zone opérée (ex. paris, nantes, bordeaux) ; language est fr ou en pour le v2.2.

Feeds & versions

Feed Contenu
system_informationMétadonnées de l'opérateur et de la région (nom, fuseau horaire, langue, contact).
vehicle_typesTypes de véhicules exploités (vélo, trottinette électrique…) et leurs caractéristiques.
free_bike_status (v2.2) / vehicle_status (v3.0)Position et disponibilité en temps réel de chaque véhicule en free-floating.
station_informationPosition et attributs statiques des stations.
station_statusOccupation et disponibilité en temps réel des stations.
system_pricing_plansGrille tarifaire applicable à la région.
geofencing_zonesZones de restriction (no-parking, no-ride, vitesse réduite…).
i

ttl est toujours à 0 : les feeds temps réel doivent être récupérés à chaque besoin, sans mise en cache côté partenaire au-delà de quelques secondes.

Champ véhicule

free_bike_status suit le schéma GBFS standard, étendu par Pony avec les champs préfixés _ ci-dessous.

Champ Type Description
bike_idstringIdentifiant GBFS régénéré à chaque appel — ne pas utiliser pour un suivi persistant, préférer _vehicle_id.
_vehicle_idstringIdentifiant stable du véhicule ([A-Za-z0-9_-], ≤ 200 caractères).
lat / lonfloatPosition GPS courante.
current_fuel_percentfloatNiveau de batterie, entre 0.0 et 1.0.
is_disabledbooleanVéhicule hors-service / offline.
station_idstringPrésent seulement si le véhicule est actuellement rattaché à une station.
_max_speedintVitesse maximale actuellement autorisée sur le véhicule, en km/h.
_battery_hatch_lockedbooleanÉtat de verrouillage de la trappe batterie.
_onlinebooleanConnectivité IoT du véhicule.
{
  "last_updated": 1704793525,
  "ttl": 0,
  "version": "2.2",
  "data": {
    "bikes": [
      {
        "bike_id": "pony_c53dd513d7ad4dad8b9471a8e0fbe45a",
        "_vehicle_id": "ec00200b",
        "lat": 48.866667,
        "lon": 2.333333,
        "current_fuel_percent": 0.33,
        "is_disabled": false,
        "station_id": "s00133a",
        "_max_speed": 23,
        "_battery_hatch_locked": true,
        "_online": true
      }
    ]
  }
}

Champ station

Champ Type Description
station_idstringIdentifiant stable de la station.
namestringNom public affichable de la station.
lat / lonfloatPosition GPS.
is_virtual_stationbooleanZone logique sans infrastructure physique.
_vehicle_idsstring[]Véhicules actuellement rattachés à la station.
_battery_levelfloatNiveau de batterie de la borne, entre 0.0 et 1.0 (le cas échéant).
{
  "last_updated": 1704793525,
  "ttl": 0,
  "version": "2.2",
  "data": {
    "stations": [
      {
        "station_id": "s00133a",
        "name": "Bordeaux place du Rocher",
        "lat": 44.8519577,
        "lon": -0.5947185,
        "is_virtual_station": false,
        "_vehicle_ids": ["ec00200b", "ec00201b"],
        "_battery_level": 0.86
      }
    ]
  }
}
GBFS · Pony Partner APIs Standard officiel : github.com/MobilityData/gbfs
Réservé aux villes & agences

MDS

La Mobility Data Specification fournit aux villes les données réglementaires de suivi de flotte : trajets terminés et changements d'état des véhicules. Chaque agence (ex. mairie) reçoit sa propre clé, restreinte à cette API.

Pony provider_id (registre officiel MDS) — identique au gbfs_pony_system_id

f190d330-b49e-4590-871b-0bcbec565a8c

Trips

Retourne tous les trajets terminés jusqu'à l'heure indiquée : « donne-moi tous les trajets qui se sont terminés dans la dernière heure ».

GET https://mds-dev.getapony.com/v1/{city}/trips?end_time={end_time}&key={api_key}https://mds.getapony.com/v1/{city}/trips?end_time={end_time}&key={api_key}
curl "https://mds-dev.getapony.com/v1/paris/trips?end_time=2026-09-11T15&key={api_key}"
curl "https://mds.getapony.com/v1/paris/trips?end_time=2026-09-11T15&key={api_key}"
{
  "version": "1.0.0",
  "data": {
    "trips": [
      {
        "provider_id": "f190d330-b49e-4590-871b-0bcbec565a8c",
        "provider_name": "Pony",
        "device_id": "1f035766-9d25-40af-b1e1-e832cd06d10b",
        "vehicle_id": "S00789",
        "vehicle_type": "scooter",
        "propulsion_types": ["electric"],
        "trip_id": "85d20361-27f0-400d-a5cb-5edc2b225fbf",
        "trip_duration": 180,
        "trip_distance": 600,
        "start_time": 1606997981,
        "end_time": 1606998161,
        "publication_time": 1606998161,
        "accuracy": 10,
        "route": {
          "type": "FeatureCollection",
          "features": [
            { "type": "Feature", "properties": { "timestamp": 1606997981 },
              "geometry": { "type": "Point", "coordinates": [48.853744, 2.3468297] } },
            { "type": "Feature", "properties": { "timestamp": 1606998161 },
              "geometry": { "type": "Point", "coordinates": [48.856882, 2.3415603] } }
          ]
        }
      }
    ]
  }
}

Détail complet des champs : spec MDS — Trips.

Status Changes

Retourne tous les changements d'état survenus jusqu'à l'heure indiquée (ex. véhicule 1 : availableunavailable suite à un unlock). Un même véhicule peut apparaître plusieurs fois si plusieurs événements se sont produits dans la fenêtre.

GET https://mds-dev.getapony.com/v1/{city}/status_changes?end_time={end_time}&key={api_key}https://mds.getapony.com/v1/{city}/status_changes?end_time={end_time}&key={api_key}
curl "https://mds-dev.getapony.com/v1/paris/status_changes?end_time=2026-09-11T15&key={api_key}"
curl "https://mds.getapony.com/v1/paris/status_changes?end_time=2026-09-11T15&key={api_key}"
{
  "version": "1.0.0",
  "data": {
    "status_changes": [
      {
        "provider_id": "f190d330-b49e-4590-871b-0bcbec565a8c",
        "provider_name": "Pony",
        "device_id": "1f035766-9d25-40af-b1e1-e832cd06d10b",
        "vehicle_id": "S00789",
        "vehicle_type": "scooter",
        "vehicle_state": "on_trip",
        "propulsion_types": ["electric"],
        "event_types": ["trip_start"],
        "event_time": 1606998064,
        "publication_time": 1606998064,
        "battery_pct": 0.9,
        "trip_id": "85d20361-27f0-400d-a5cb-5edc2b225fbf",
        "event_location": {
          "type": "Feature",
          "properties": { "timestamp": 1606998064 },
          "geometry": { "type": "Point", "coordinates": [48.853744, 2.3468297] }
        }
      }
    ]
  }
}

Machine à états complète (événements ↔ statuts) : diagramme officiel · spec MDS — Status Changes.

MDS · Pony Partner APIs Standard officiel : Open Mobility Foundation
Réservé aux villes & agences

NeTEx

NeTEx (Network Timetable Exchange, norme CEN/TS 16614) est le format d'échange XML européen utilisé par les autorités organisatrices de mobilité. Pony expose, par zone opérée, un export NeTEx v6 décrivant son offre de mobilité partagée.

Endpoint

Le fichier est servi sur la même API que MDS, avec la même clé key par agence.

GET https://mds-dev.getapony.com/{version}/netex/v6/regions/{region}?key={api_key}https://mds.getapony.com/{version}/netex/v6/regions/{region}?key={api_key}
curl "https://mds-dev.getapony.com/v1/netex/v6/regions/paris?key={api_key}" -o pony_netex_paris.xml
curl "https://mds.getapony.com/v1/netex/v6/regions/paris?key={api_key}" -o pony_netex_paris.xml

region est l'identifiant de zone (ex. paris). La réponse est un fichier application/xml nommé pony_netex_{region}.xml.

Structure du flux

Le document suit l'ossature standard NeTEx : un PublicationDelivery racine contenant un dataObjects / CompositeFrame, lui-même composé de frames spécialisées :

  • ResourceFrame — opérateur, réseau et types de véhicules (équivalent NeTEx de system_information / vehicle_types en GBFS).
  • SiteFrame — sites et points d'accès, dont les stations de la zone.
  • ServiceFrame — l'offre de mobilité partagée elle-même (zones de service, contraintes de dépôt).
<PublicationDelivery xmlns="http://www.netex.org.uk/netex">
  <PublicationTimestamp>2026-09-11T15:00:00Z</PublicationTimestamp>
  <ParticipantRef>PONY</ParticipantRef>
  <dataObjects>
    <CompositeFrame id="PONY:CompositeFrame:paris" version="1">
      <frames>
        <ResourceFrame />
        <SiteFrame />
        <ServiceFrame />
      </frames>
    </CompositeFrame>
  </dataObjects>
</PublicationDelivery>
i

Ce squelette suit la norme NeTEx générique ; le détail exact des éléments (identifiants, versions de profil) est confirmé à l'onboarding selon les exigences de votre autorité organisatrice.

NeTEx · Pony Partner APIs Norme officielle : netex-cen.eu
Intégration poussée

MaaS

L'API MaaS permet de vendre le trajet Pony à l'intérieur de votre propre application : localiser les véhicules, envoyer des commandes (déverrouiller, verrouiller, sonner…), suivre les trajets et gérer les coupons de vos utilisateurs.

Auth & app_id

api_key

Passé en query param sur chaque appel : api_key=XXXX. Vous transmettez alors votre propre external_user_id.

Pour GBFS, utilisez une clé GBFS dédiée (key=XXXX), distincte de la clé MaaS.

pony auth token (à venir)

Header Authorization: Bearer {auth_token}, lié à un utilisateur Pony précis. Ne pas transmettre d'external_user_id dans ce cas — Pony retrouve l'utilisateur depuis le token.

app_id identifie votre intégration sur tous les appels GBFS et commandes véhicule : app_id=YYYY, en query param systématiquement.

curl "https://partners-dev.getapony.com/v0/users/user_XXXX/ongoing_trip?api_key=XXXX&app_id=YYYY"
curl "https://partners.getapony.com/v0/users/user_XXXX/ongoing_trip?api_key=XXXX&app_id=YYYY"

Seuils de batterie

La batterie du véhicule est exposée en continu via GBFS (current_fuel_percent). Trois seuils gouvernent le comportement du véhicule :

Seuil Défaut Effet
Refus de déverrouillage6%Sous ce niveau, le véhicule refuse tout nouveau trajet.
Fin d'assistance6%L'assistance électrique du véhicule est coupée.
Verrouillage forcé5%Le véhicule se verrouille et le trajet en cours se termine automatiquement.

Format des réponses & erreurs

Succèshttp_code 200, corps JSON spécifique à l'appel.

Échechttp_code 400, avec toujours :

{ "status": "failed", "error": "ERROR_CODE" }
error Description
UNKNOWN_ERRORErreur générique non attendue.
VALIDATION_ERRORPayload mal formé — détail dans validation_output.
UNKNOWN_APP_IDapp_id non reconnu.
{
  "status": "failed",
  "error": "VALIDATION_ERROR",
  "validation_output": {
    "app_id": ["Missing data for required field."]
  }
}
!

error et error_description sont destinés au debug : ne jamais les afficher tels quels à l'utilisateur final.

Chaque endpoint peut ajouter ses propres codes d'erreur en complément de ce socle commun — voir chaque section ci-dessous.

Coupons

Utiliser un coupon

POST https://partners-dev.getapony.com/v1/coupons/{coupon}/redeemhttps://partners.getapony.com/v1/coupons/{coupon}/redeem

Historique des coupons

GET https://partners-dev.getapony.com/v0/users/{user_id}/benefitshttps://partners.getapony.com/v0/users/{user_id}/benefits
{
  "data": [
    {
      "coupon": "EASTER",
      "title": "-50% sur 3 trajet(s)",
      "subtitle": "0 / 3 trajet(s) restant(s)",
      "effective_end_at": "2030-01-01T00:00:00Z",
      "conditions": ["30 min par trajet (max)"],
      "expired": false
    }
  ]
}

Trajets

Historique des trajets

GET https://partners-dev.getapony.com/v0/users/{user_id}/trips?starting_after={xxx}https://partners.getapony.com/v0/users/{user_id}/trips?starting_after={xxx}
{
  "has_more": false,
  "data": [
    { "_id": "trip_...", "startTime": "2030-01-01T00:00:00Z", "endTime": "2030-01-01T00:00:00Z" }
  ]
}

Trajet en cours

Renvoie le trajet actuellement en cours pour un utilisateur, c'est-à-dire déverrouillé et non encore verrouillé/terminé (un trajet en pause reste « en cours »).

GET https://partners-dev.getapony.com/v0/users/{external_user_id}/ongoing_trip?api_key=XXXX&app_id=YYYYhttps://partners.getapony.com/v0/users/{external_user_id}/ongoing_trip?api_key=XXXX&app_id=YYYY
{
  "_id": "trip_...",
  "startTime": "2030-01-01T00:00:00+00:00"
}
error http_code Description
NO_ONGOING_TRIP400Aucun trajet en cours pour cet utilisateur (y compris si Pony ne le connaît pas).
VALIDATION_ERROR400app_id / api_key manquant ou invalide.
401app_id inconnu ou api_key invalide — corps {"error": "..."}.

Véhicules

La liste des véhicules est fournie par le flux GBFS, avec une clé GBFS dédiée qui débloque les champs étendus (voir champ véhicule).

Tous les véhicules

GET https://gbfs-dev.getapony.com/v1/{region}/{language}/free_bike_status.json?key={gbfs_api_key}https://gbfs.getapony.com/v1/{region}/{language}/free_bike_status.json?key={gbfs_api_key}

Filtrage possible via &vehicle_id={id} pour ne récupérer qu'un seul véhicule (correspondance stricte).

Stations

La liste des stations est fournie par le flux GBFS, avec les mêmes champs étendus (voir champ station).

Toutes les stations

GET https://gbfs-dev.getapony.com/v1/{region}/{language}/station_information.jsonhttps://gbfs.getapony.com/v1/{region}/{language}/station_information.json

Commandes véhicule

POST https://partners-dev.getapony.com/v1/vehicles/{vehicle_id}/commandhttps://partners.getapony.com/v1/vehicles/{vehicle_id}/command

Payload commun

Champ Requis Type Description
commandrequisstringLa commande envoyée, ex. "unlock".
lat / lonrequisfloatPosition de l'appelant.
external_trip_idoptionnelstringVotre identifiant de trajet ([A-Za-z0-9_-], ≤ 200 car.).
external_user_idoptionnelstringVotre identifiant utilisateur — obligatoire si vous n'utilisez pas de pony auth token.
external_agent_idoptionnelstringIdentifiant agent/logistique, si l'appelant n'est pas un simple utilisateur.
error Description
UNKNOWN_VEHICLE_IDIdentifiant véhicule non reconnu.
UNKNOWN_VEHICLE_COMMANDCommande non reconnue.
VEHICLE_OFFLINELe véhicule est hors-ligne au moment de l'appel (race condition possible).
VEHICLE_NOT_AVAILABLEVéhicule indisponible pour une autre raison.

unlock

Déverrouille le véhicule et démarre le trajet associé. Champs additionnels : max_speed (int, requis), nfc_scan_id (optionnel).

curl -X POST https://partners-dev.getapony.com/v1/vehicles/ec00200b/command \
  -H 'Content-Type: application/json' \
  -d '{"command":"unlock","external_trip_id":"trip_00467","external_user_id":"user_0009","lat":49.866699,"lon":2.333378,"max_speed":23}'
curl -X POST https://partners.getapony.com/v1/vehicles/ec00200b/command \
  -H 'Content-Type: application/json' \
  -d '{"command":"unlock","external_trip_id":"trip_00467","external_user_id":"user_0009","lat":49.866699,"lon":2.333378,"max_speed":23}'
{"status": "succeeded", "trip_id": "trip_..."}

Erreurs spécifiques : TRIP_ALREADY_STARTED · VEHICLE_ALREADY_IN_TRIP (un autre utilisateur a déjà démarré un trajet) · VEHICLE_UNLOCK_FAIL (souvent batterie trop faible).

end_trip_check

Avant de verrouiller réellement, vérifie que la position permet de terminer le trajet.

{ "end_trip_flow": "TAKE_PICTURE", "error_description": "xxx" }

Si end_trip_flow = TAKE_PICTURE, l'utilisateur peut poursuivre le flux de fin de trajet ; sinon, affichez error_description et bloquez l'étape suivante.

lock

Verrouille le véhicule et termine le trajet. Appel synchrone : bloque jusqu'au verrouillage effectif ou jusqu'à un timeout de 30 s.

curl -X POST https://partners-dev.getapony.com/v1/vehicles/ec00200b/command \
  -H 'Content-Type: application/json' \
  -d '{"command":"lock","external_trip_id":"trip_00467","external_user_id":"user_0009"}'
curl -X POST https://partners.getapony.com/v1/vehicles/ec00200b/command \
  -H 'Content-Type: application/json' \
  -d '{"command":"lock","external_trip_id":"trip_00467","external_user_id":"user_0009"}'
{"status": "succeeded"}

Erreurs : UNKNOWN_TRIP_ID · TRIP_ALREADY_ENDED · VEHICLE_LOCK_TIMEOUT (timeout 30 s dépassé).

pause

Verrouille le véhicule sans terminer le trajet. Également synchrone (timeout 30 s).

{"status": "succeeded"}

Mêmes erreurs que lock : UNKNOWN_TRIP_ID · TRIP_ALREADY_ENDED · VEHICLE_LOCK_TIMEOUT.

resume

Redéverrouille un véhicule déjà en trajet (sortie de pause). Champ additionnel : max_speed (int, requis).

{"status": "succeeded"}

Erreur spécifique : VEHICLE_ALREADY_IN_TRIP.

unlock_battery_hatch

Déverrouille la trappe batterie. Réservé à un agent : external_agent_id requis.

{"status": "succeeded"}

Erreur spécifique : VEHICLE_ALREADY_IN_TRIP (impossible d'ouvrir la trappe pendant un trajet).

ring

Déclenche le bip sonore du véhicule (typiquement pour un agent logistique). external_agent_id requis.

{"status": "succeeded"}

Erreur spécifique : VEHICLE_ALREADY_IN_TRIP (ne jamais faire sonner un véhicule occupé par un utilisateur en trajet — risque de surprise/danger).

set_max_speed

Ajuste la vitesse maximale du véhicule, en km/h. Champ additionnel : max_speed (int, requis, entre 1 et 25 — limite légale).

{
  "status": "failed",
  "error": "VALIDATION_ERROR",
  "validation_output": "The max_speed must be between 1 & 25 km/h"
}

Erreurs : UNKNOWN_TRIP_ID · TRIP_ALREADY_ENDED · VALIDATION_ERROR (vitesse hors bornes).

Webhooks

Pony notifie votre plateforme en HTTPS, avec la même authentification que le reste de l'API MaaS : api_key et app_id en query params.

POST https://{SPECIFIC_PARTNER_DOMAIN}/{WEBHOOK_SERVICE_URL}/

Mise à jour véhicule

Déclenché à chaque changement d'état d'un véhicule (ex. scan NFC).

POST https://{SPECIFIC_PARTNER_DOMAIN}/{WEBHOOK_SERVICE_URL}/vehicule?api_key={ZZZZ}&app_id={BBBB}
curl -X POST https://partner-domain.com/pony_webhook/vehicule?api_key=ZZZZ&app_id=BBBB \
  -H 'Content-Type: application/json' \
  -d '{"vehicle_id":"ec00200b","locked":true,"position":{"type":"Point","coordinates":[48.866667,2.333333]},"battery_level":0.33,"online":true,"status":"in_trip","station_id":"s00133a","max_speed":23,"battery_hatch_locked":true}'
{"status": "succeeded"}

Relances & timeout

Si l'appel échoue (code ≠ 200), Pony relance avec un backoff exponentiel — 3 tentatives sur 5 minutes, timeout de 10 s par tentative :

Tentative Délai depuis l'échec initial
Relance 1+75 s
Relance 2+150 s
Relance 3+300 s (soit 5 min au total)
MaaS · Pony Partner APIs Une question d'intégration ? partners-tech@getapony.com