Se connecter

API

Crée des voyages, gère des itinéraires et collabore via une API REST simple.

Authentification

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"

Scopes

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.

SDKs

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.

TypeScript

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);
}

Model Context Protocol

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

Full MCP setup instructions →

Limitation de débit

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.

ParameterTypeDescription
X-RateLimit-LimitintegerRequêtes autorisées par fenêtre
X-RateLimit-RemainingintegerRequêtes restantes dans la fenêtre en cours
Retry-AfterintegerSecondes avant la réinitialisation de la fenêtre (uniquement sur 429)

Idempotency and retries

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.

Idempotency-Key header

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"}'

clientRef field

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.

Erreurs

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.

ParameterTypeDescription
UNAUTHORIZED401Clé API invalide ou manquante
FORBIDDEN403La clé n'a pas les droits requis ou l'accès au voyage
NOT_FOUND404La ressource n'existe pas
VALIDATION_ERROR400Champs de requête manquants ou invalides
IDEMPOTENCY_CONFLICT409Same Idempotency-Key was replayed with a different request body
RATE_LIMITED429Trop de requêtes

Points d'accès

Me

GET/me

Return 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_..."

Voyages

GET/trips

Liste tous les voyages auxquels l'utilisateur authentifié a accès.

curl https://keen-sturgeon-487.convex.site/api/v1/trips \
  -H "Authorization: Bearer osk_..."
POST/trips

Crée un nouveau voyage.

ParameterTypeDescription
groupId*stringGroupe dans lequel créer le voyage
title*stringTitre du voyage
startDate*stringDate de début (YYYY-MM-DD)
endDate*stringDate 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"}'
GET/trips/{tripId}

Obtenir les détails du voyage.

GET/trips/{tripId}/export

Canonical 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_..."
POST/trips/{tripId}/sync

Diff-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"}]}'
PATCH/trips/{tripId}

Mettre à jour les métadonnées du voyage.

ParameterTypeDescription
titlestringNouveau titre
startDatestringNouvelle date de début
endDatestringNouvelle date de fin
statusstringdraft, active, ou completed
DELETE/trips/{tripId}

Archiver un voyage (passe le statut à completed).

Étapes du voyage

GET/trips/{tripId}/legs

Liste les étapes d'un voyage, triées par ordre.

ParameterTypeDescription
limitintegerMax results (default 100, max 200)
cursorstringPagination cursor from previous response
POST/trips/{tripId}/legs

Ajouter une étape.

ParameterTypeDescription
order*numberOrdre de tri (base 0)
title*stringTitre de l'étape
destination*stringNom de la destination
startDate*stringDate de début
endDate*stringDate de fin
timezone*stringFuseau horaire IANA (ex. Europe/London)
accommodationobjectDétails d'hébergement
flightsarrayDétails des vols
rentalCarobjectDétails de la voiture de location
clientRefstringCaller-supplied unique reference (per trip). Retries upsert instead of duplicating.
POST/trips/{tripId}/legs:batch

Batch 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"}]}'
PATCH/trips/{tripId}/legs/{legId}

Mettre à jour une étape.

DELETE/trips/{tripId}/legs/{legId}

Supprimer une étape.

Actions à faire

GET/trips/{tripId}/action-items

Liste les éléments de la checklist pour un voyage.

POST/trips/{tripId}/action-items

Créer un élément de checklist.

ParameterTypeDescription
text*stringTexte de l'élément
urgency*stringnow, before_trip, ou nice_to_have
ownerstringID utilisateur à assigner
clientRefstringCaller-supplied unique reference (per trip). Retries upsert instead of duplicating.
POST/trips/{tripId}/action-items:batch

Batch upsert up to 50 action items. Supports clientRef for retry-safe upserts.

PATCH/trips/{tripId}/action-items/{itemId}

Mettre à jour ou cocher/décocher un élément.

DELETE/trips/{tripId}/action-items/{itemId}

Supprimer un élément.

Commitments

GET/trips/{tripId}/commitments

List scheduled events on a trip: dinners, activities, birthdays, meetings. Paginated — default limit 100, max 200, ordered by startDate and startTime.

POST/trips/{tripId}/commitments

Create a scheduled event. Optionally link it to a leg or a map pin.

ParameterTypeDescription
title*stringEvent title
startDate*stringDate (YYYY-MM-DD)
category*stringdinner, activity, birthday, meeting, or other
startTimestringLocal time HH:mm (24-hour)
endTimestringLocal time HH:mm (24-hour)
isAllDaybooleanTrue for all-day events (startTime and endTime are ignored)
timezonestringIANA timezone (e.g., Europe/London)
legIdstringLink to an existing trip leg
mapPinIdstringLink to an existing map pin
notesstringFree-form notes about the event
PATCH/trips/{tripId}/commitments/{commitmentId}

Update a commitment.

DELETE/trips/{tripId}/commitments/{commitmentId}

Remove a commitment.

Épingles de carte

GET/trips/{tripId}/map-pins

Liste les épingles de carte pour un voyage.

POST/trips/{tripId}/map-pins

Épingler un lieu sur la carte du voyage.

ParameterTypeDescription
name*stringNom du lieu
lat*numberLatitude
lng*numberLongitude
categorystringCatégorie (ex. restaurant, hôtel)
notesstringNotes sur le lieu
clientRefstringCaller-supplied unique reference (per trip). Retries upsert instead of duplicating.
POST/trips/{tripId}/map-pins:batch

Batch upsert up to 50 map pins. Supports clientRef for retry-safe upserts.

PATCH/trips/{tripId}/map-pins/{pinId}

Mettre à jour une épingle.

DELETE/trips/{tripId}/map-pins/{pinId}

Supprimer une épingle.

Messages

GET/trips/{tripId}/channels

Liste les canaux d'un voyage.

GET/trips/{tripId}/channels/{channelId}/messages

Liste les messages d'un canal. Paginé : passe le curseur pour la page suivante.

ParameterTypeDescription
limitintegerRésultats max (par défaut 50, max 100)
cursorstringCurseur de pagination de la réponse précédente
POST/trips/{tripId}/channels/{channelId}/messages

Envoyer un message dans un canal.

ParameterTypeDescription
content*stringContenu du message
parentIdstringRépondre à un ID de message

Membres du voyage

GET/trips/{tripId}/members

Liste les membres d'un voyage avec leurs rôles et coordonnées.

Shared (no auth)

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.

GET/shared/trips/{token}

Read-only share view. No Authorization header required.

curl https://keen-sturgeon-487.convex.site/api/v1/shared/trips/SHARE_TOKEN
GET/shared/trips/{token}/export

Canonical share snapshot with the same shape as /trips/{tripId}/export but using the safe-allowlist projection.