Crée des voyages, gère des itinéraires et collabore via une API REST simple.
Toutes les requêtes API nécessitent une clé API envoyée comme Bearer token dans le header Authorization.
Génère une clé dans Paramètres → Clés API. Copie la clé immédiatement. Elle ne sera plus affichée.
curl https://keen-sturgeon-487.convex.site/api/v1/trips \ -H "Authorization: Bearer osk_your_key_here"
The four base scopes are trips:read, trips:write, messages:read, and messages:write. Each can be limited to a single trip by appending :<tripId>. For example, a key with only the scope trips:write:jx7abc... can create and update content on that one trip but nothing else. In the settings UI, leave "Limit to trip" blank for a key that works everywhere, or paste a trip ID to scope it down.
You do not need a client to use the REST API, but the official TypeScript SDK takes care of the tedious bits: auto-generated idempotency keys, retry with exponential backoff on 429 and 5xx, cursor pagination iterators, typed errors, and an unauthenticated share-token consumer.
npm install @osoto/api-client
import { OsotoClient } from '@osoto/api-client';
const client = new OsotoClient({
apiKey: process.env.OSOTO_API_KEY!,
baseUrl: 'https://keen-sturgeon-487.convex.site/api/v1',
});
const me = await client.me();
const { _id: tripId } = await client.createTrip({
groupId: me.defaultGroupId!,
title: 'Cotswolds',
startDate: '2026-07-15',
endDate: '2026-07-22',
});
// Async iterator loops every page automatically.
for await (const leg of client.iterateLegs(tripId)) {
console.log(leg.title);
}Agents that speak MCP (Claude Desktop, Claude Code, Cursor, Windsurf, OpenClaw) can consume the REST API through @osoto/mcp-server without writing any client code.
npx @osoto/mcp-server
Les clés API sont limitées à 60 requêtes par minute. Le statut de la limite est renvoyé dans les headers de réponse.
| Parameter | Type | Description |
|---|---|---|
| X-RateLimit-Limit | integer | Requêtes autorisées par fenêtre |
| X-RateLimit-Remaining | integer | Requêtes restantes dans la fenêtre en cours |
| Retry-After | integer | Secondes avant la réinitialisation de la fenêtre (uniquement sur 429) |
Retries are safe. You have two tools for making sure a flaky network does not create duplicates: an Idempotency-Key header for individual mutations, and a clientRef field for upserting rows by a caller-supplied identifier.
Any POST, PATCH, or DELETE may include an Idempotency-Key header (max 255 characters). Retries with the same key replay the cached response; retries with the same key but a different body return 409 IDEMPOTENCY_CONFLICT. Cached responses expire after 24 hours.
curl -X POST https://keen-sturgeon-487.convex.site/api/v1/trips \
-H "Authorization: Bearer osk_..." \
-H "Idempotency-Key: create-trip-42" \
-H "Content-Type: application/json" \
-d '{"groupId":"...","title":"Cotswolds","startDate":"2026-07-15","endDate":"2026-07-22"}'Pass a clientRef when creating legs, action items, map pins, or stays. It is unique per trip (or per leg for stays). Passing the same value on a retry diff-merges into the existing row instead of inserting a duplicate. clientRef pairs naturally with the batch upsert endpoints when importing a full itinerary.
Les erreurs retournent un objet JSON avec un code et un message.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Missing required fields: title, startDate",
"requestId": "req_0f9a8b7c-...",
"details": [
{ "path": "title", "reason": "required" },
{ "path": "startDate", "reason": "required" }
]
}
}Every response carries an X-Request-Id header (mirrored in error.requestId for error responses). Include it when filing support issues so we can trace the request end-to-end.
| Parameter | Type | Description |
|---|---|---|
| UNAUTHORIZED | 401 | Clé API invalide ou manquante |
| FORBIDDEN | 403 | La clé n'a pas les droits requis ou l'accès au voyage |
| NOT_FOUND | 404 | La ressource n'existe pas |
| VALIDATION_ERROR | 400 | Champs de requête manquants ou invalides |
| IDEMPOTENCY_CONFLICT | 409 | Same Idempotency-Key was replayed with a different request body |
| RATE_LIMITED | 429 | Trop de requêtes |
/meReturn the authenticated user, their groups, and the default group ID. Call this once at startup to discover groupId values for trip creation.
curl https://keen-sturgeon-487.convex.site/api/v1/me \ -H "Authorization: Bearer osk_..."
/tripsListe tous les voyages auxquels l'utilisateur authentifié a accès.
curl https://keen-sturgeon-487.convex.site/api/v1/trips \ -H "Authorization: Bearer osk_..."
/tripsCrée un nouveau voyage.
| Parameter | Type | Description |
|---|---|---|
| groupId* | string | Groupe dans lequel créer le voyage |
| title* | string | Titre du voyage |
| startDate* | string | Date de début (YYYY-MM-DD) |
| endDate* | string | Date de fin (YYYY-MM-DD) |
curl -X POST https://keen-sturgeon-487.convex.site/api/v1/trips \
-H "Authorization: Bearer osk_..." \
-H "Content-Type: application/json" \
-d '{"groupId":"...","title":"Summer in the Cotswolds","startDate":"2026-07-15","endDate":"2026-07-22"}'/trips/{tripId}Obtenir les détails du voyage.
/trips/{tripId}/exportCanonical trip snapshot. Returns trip, legs, map pins, action items, commitments, and members in a single response. Use this to answer questions like "where am I staying on Tuesday" without issuing multiple reads.
curl https://keen-sturgeon-487.convex.site/api/v1/trips/TRIP_ID/export \ -H "Authorization: Bearer osk_..."
/trips/{tripId}/syncDiff-based snapshot import. Pass any combination of legs, actionItems, and mapPins; items with a matching clientRef are diff-merged, items without are created. Set dryRun=true to preview the change set without writing. Returns per-category created/updated/errors counts and per-item outcomes.
curl -X POST "https://keen-sturgeon-487.convex.site/api/v1/trips/TRIP_ID/sync?dryRun=true" \
-H "Authorization: Bearer osk_..." \
-H "Content-Type: application/json" \
-d '{"legs":[{"order":0,"title":"Tokyo","destination":"Tokyo","startDate":"2026-07-15","endDate":"2026-07-20","timezone":"Asia/Tokyo","clientRef":"leg-tok-1"}],"mapPins":[{"name":"Sensoji","lat":35.7148,"lng":139.7967,"clientRef":"pin-sensoji"}]}'/trips/{tripId}Mettre à jour les métadonnées du voyage.
| Parameter | Type | Description |
|---|---|---|
| title | string | Nouveau titre |
| startDate | string | Nouvelle date de début |
| endDate | string | Nouvelle date de fin |
| status | string | draft, active, ou completed |
/trips/{tripId}Archiver un voyage (passe le statut à completed).
/trips/{tripId}/legsListe les étapes d'un voyage, triées par ordre.
| Parameter | Type | Description |
|---|---|---|
| limit | integer | Max results (default 100, max 200) |
| cursor | string | Pagination cursor from previous response |
/trips/{tripId}/legsAjouter une étape.
| Parameter | Type | Description |
|---|---|---|
| order* | number | Ordre de tri (base 0) |
| title* | string | Titre de l'étape |
| destination* | string | Nom de la destination |
| startDate* | string | Date de début |
| endDate* | string | Date de fin |
| timezone* | string | Fuseau horaire IANA (ex. Europe/London) |
| accommodation | object | Détails d'hébergement |
| flights | array | Détails des vols |
| rentalCar | object | Détails de la voiture de location |
| clientRef | string | Caller-supplied unique reference (per trip). Retries upsert instead of duplicating. |
/trips/{tripId}/legs:batchBatch upsert up to 50 legs in a single call. Items with a matching clientRef are diff-merged; items without are created. Partial success: a 207 response lists per-item results.
curl -X POST https://keen-sturgeon-487.convex.site/api/v1/trips/TRIP_ID/legs:batch \
-H "Authorization: Bearer osk_..." \
-H "Content-Type: application/json" \
-d '{"items":[{"order":0,"title":"Tokyo","destination":"Tokyo","startDate":"2026-07-15","endDate":"2026-07-20","timezone":"Asia/Tokyo","clientRef":"leg-tok-1"}]}'/trips/{tripId}/legs/{legId}Mettre à jour une étape.
/trips/{tripId}/legs/{legId}Supprimer une étape.
/trips/{tripId}/action-itemsListe les éléments de la checklist pour un voyage.
/trips/{tripId}/action-itemsCréer un élément de checklist.
| Parameter | Type | Description |
|---|---|---|
| text* | string | Texte de l'élément |
| urgency* | string | now, before_trip, ou nice_to_have |
| owner | string | ID utilisateur à assigner |
| clientRef | string | Caller-supplied unique reference (per trip). Retries upsert instead of duplicating. |
/trips/{tripId}/action-items:batchBatch upsert up to 50 action items. Supports clientRef for retry-safe upserts.
/trips/{tripId}/action-items/{itemId}Mettre à jour ou cocher/décocher un élément.
/trips/{tripId}/action-items/{itemId}Supprimer un élément.
/trips/{tripId}/commitmentsList scheduled events on a trip: dinners, activities, birthdays, meetings. Paginated — default limit 100, max 200, ordered by startDate and startTime.
/trips/{tripId}/commitmentsCreate a scheduled event. Optionally link it to a leg or a map pin.
| Parameter | Type | Description |
|---|---|---|
| title* | string | Event title |
| startDate* | string | Date (YYYY-MM-DD) |
| category* | string | dinner, activity, birthday, meeting, or other |
| startTime | string | Local time HH:mm (24-hour) |
| endTime | string | Local time HH:mm (24-hour) |
| isAllDay | boolean | True for all-day events (startTime and endTime are ignored) |
| timezone | string | IANA timezone (e.g., Europe/London) |
| legId | string | Link to an existing trip leg |
| mapPinId | string | Link to an existing map pin |
| notes | string | Free-form notes about the event |
/trips/{tripId}/commitments/{commitmentId}Update a commitment.
/trips/{tripId}/commitments/{commitmentId}Remove a commitment.
/trips/{tripId}/map-pinsListe les épingles de carte pour un voyage.
/trips/{tripId}/map-pinsÉpingler un lieu sur la carte du voyage.
| Parameter | Type | Description |
|---|---|---|
| name* | string | Nom du lieu |
| lat* | number | Latitude |
| lng* | number | Longitude |
| category | string | Catégorie (ex. restaurant, hôtel) |
| notes | string | Notes sur le lieu |
| clientRef | string | Caller-supplied unique reference (per trip). Retries upsert instead of duplicating. |
/trips/{tripId}/map-pins:batchBatch upsert up to 50 map pins. Supports clientRef for retry-safe upserts.
/trips/{tripId}/map-pins/{pinId}Mettre à jour une épingle.
/trips/{tripId}/map-pins/{pinId}Supprimer une épingle.
/trips/{tripId}/channelsListe les canaux d'un voyage.
/trips/{tripId}/channels/{channelId}/messagesListe les messages d'un canal. Paginé : passe le curseur pour la page suivante.
| Parameter | Type | Description |
|---|---|---|
| limit | integer | Résultats max (par défaut 50, max 100) |
| cursor | string | Curseur de pagination de la réponse précédente |
/trips/{tripId}/channels/{channelId}/messagesEnvoyer un message dans un canal.
| Parameter | Type | Description |
|---|---|---|
| content* | string | Contenu du message |
| parentId | string | Répondre à un ID de message |
/trips/{tripId}/membersListe les membres d'un voyage avec leurs rôles et coordonnées.
Generate a share token with POST /trips/{tripId}/share-token. The token grants unauthenticated read access to the safe projection of the trip. Sensitive fields like wifiPassword, doorCode, hostPhone, confirmationNumber, and check-in instructions are stripped. Revoke with DELETE /trips/{tripId}/share-token.
/shared/trips/{token}Read-only share view. No Authorization header required.
curl https://keen-sturgeon-487.convex.site/api/v1/shared/trips/SHARE_TOKEN
/shared/trips/{token}/exportCanonical share snapshot with the same shape as /trips/{tripId}/export but using the safe-allowlist projection.