Apparence
Démarrage rapide
Ce guide part d'un compte vide et arrive à une réservation encaissée. Comptez une trentaine de minutes. Chaque étape est autonome et donne le code exact à exécuter.
Le fil rouge : vendre des places pour un concert du 12 mars dans la salle Olympia.
Avant de commencer
Vous avez besoin d'un compte sur bo.mitoera.com et d'un terminal. Tout ce qui suit fonctionne aussi en mode sandbox, sans conséquence sur vos données de production — c'est même recommandé pour un premier essai.
Étape 1 — Récupérer ses clés API
Dans le back-office, ouvrez Clés API et créez deux clés :
| Clé | Format | Où l'utiliser |
|---|---|---|
| Clé secrète (backoffice) | pk_xxxxxxxx:sk_xxxxxxxx | Serveur uniquement |
| Clé publique | pk_live_xxxxxxxx (prod) · pk_test_xxxxxxxx (sandbox) | Front-end, dans le widget |
Ne publiez jamais la clé secrète
Elle donne un accès complet en écriture à votre workspace. Elle ne doit jamais apparaître dans du code envoyé au navigateur, ni dans un dépôt Git. Stockez-la en variable d'environnement.
Le détail des deux types de clés est sur la page Clés API.
Étape 2 — Installer le SDK
Vous pouvez tout faire en HTTP brut, mais le SDK évite d'écrire l'authentification et le parsing à la main.
bash
npm install @mitoera/sdkbash
composer require mitoera/php-sdk:^1.0bash
# Rien à installer : cURL ou fetch suffisent.
# Voir la référence API : /api/Versions
mitoera/php-sdk est en v1.0.1, @mitoera/sdk en 0.1.0 — ce dernier étant en 0.x, épinglez-le si votre chaîne de build ne le fait pas. Les deux sont sous licence MIT et sans dépendance de production.
Initialisez ensuite le client avec votre clé secrète :
ts
import { MitoeraClient } from '@mitoera/sdk';
const client = new MitoeraClient({
keyId: process.env.MITOERA_KEY_ID, // pk_xxxxxxxx
secret: process.env.MITOERA_SECRET, // sk_xxxxxxxx
});php
use Mitoera\Sdk\MitoeraClient;
$client = new MitoeraClient([
'keyId' => getenv('MITOERA_KEY_ID'), // pk_xxxxxxxx
'secret' => getenv('MITOERA_SECRET'), // sk_xxxxxxxx
]);Étape 3 — Créer le plan de salle
Un plan naît vide, puis on lui ajoute ses sièges.
ts
const chart = await client.charts.create('Salle Olympia');
console.log(chart.id); // 01926a3f-1234-7abc-8def-000000000001php
$chart = $client->charts->create('Salle Olympia');
echo $chart->id; // 01926a3f-1234-7abc-8def-000000000001bash
curl -X POST https://api.mitoera.com/api/charts \
-u pk_xxxxxxxx:sk_xxxxxxxx \
-H 'Content-Type: application/json' \
-d '{"name":"Salle Olympia"}'Dessinez ensuite la salle. Deux voies :
- Le back-office — ouvrez le plan et placez rangées et sièges à la souris. C'est la voie recommandée pour démarrer.
- L'éditeur embarqué — le même éditeur, dans une iframe de votre propre back-office, si vos utilisateurs doivent dessiner leurs salles eux-mêmes.
Gardez l'id du plan sous la main : c'est votre chartId.
Étape 4 — Publier le plan
Un plan draft n'est pas utilisable par un événement. Il faut le publier.
ts
await client.charts.publish(chartId);php
$client->charts->publish($chartId);bash
curl -X POST https://api.mitoera.com/api/charts/CHART_ID/publish \
-u pk_xxxxxxxx:sk_xxxxxxxxToute modification ultérieure repasse pendingChanges à true : les changements existent, mais les événements continuent d'utiliser la dernière version publiée jusqu'à ce que vous republiiez.
Étape 5 — Créer l'événement
L'événement, c'est la date. Il porte un identifier textuel unique, bien plus pratique qu'un UUID dans vos URLs.
ts
const event = await client.events.create(
'Concert 12 mars', // title
'concert-12-mars', // identifier (slug unique)
chartId, // plan associé
);php
$event = $client->events->create(
'Concert 12 mars', // title
'concert-12-mars', // identifier (slug unique)
$chartId, // plan associé
);bash
curl -X POST https://api.mitoera.com/api/events \
-u pk_xxxxxxxx:sk_xxxxxxxx \
-H 'Content-Type: application/json' \
-d '{"title":"Concert 12 mars","identifier":"concert-12-mars","chartId":"CHART_ID"}'Si vous aviez créé l'événement sans plan, associez-le après coup avec linkChart(eventId, chartId).
Étape 6 — Ouvrir une session côté serveur
Avant d'afficher la page de réservation, votre back-end crée une session. Elle matérialise le panier et produit les jetons nécessaires.
ts
const session = await client.sessions.create(event.id);
// À transmettre à la page :
session.sessionToken; // pour le widget
session.holdToken; // à garder côté serveur pour confirmer plus tard
session.expiresIn; // durée de vie, en secondesphp
$session = $client->sessions->create($event->id);
// À transmettre à la page :
$session->sessionToken; // pour le widget
$session->holdToken; // à garder côté serveur pour confirmer plus tard
$session->expiresIn; // durée de vie, en secondesSession obligatoire ?
Non. Le widget sait créer sa propre session à partir de la clé publique, et vous récupérez alors les jetons dans le callback onReady. Créer la session côté serveur vous donne simplement la main dessus dès le départ — c'est plus confortable dès que le paiement entre en jeu.
Étape 7 — Afficher le plan sur votre page
La version la plus courte, sans bundler, avec la clé publique :
html
<div id="mitoera-chart" style="width:100%;height:600px"></div>
<script src="https://bo.mitoera.com/mitoera-widget.js"></script>
<script>
const chart = new Mitoera.SeatingChart({
divId: 'mitoera-chart',
workspaceKey: 'pk_live_xxxxxxxx',
event: 'concert-12-mars', // slug ou UUID
onReady: ({ sessionToken, holdToken, eventId }) => {
console.log('Widget prêt', eventId);
},
onSelectionChange: (seats) => {
document.querySelector('#total').textContent = `${seats.length} siège(s)`;
},
onCheckout: (seats) => {
// L'utilisateur a cliqué « Valider » → on part vers le paiement
demarrerPaiement(seats.map(s => s.seatKey));
},
});
chart.render();
</script>Avec un bundler (Vue, React, Svelte…), c'est le même objet importé depuis le SDK :
ts
import { SeatingChart } from '@mitoera/sdk/browser';À ce stade, votre page affiche le plan, les sièges se sélectionnent et se bloquent automatiquement. Voir SeatingChart pour les options complètes.
Étape 8 — Confirmer la réservation après paiement
Le paiement encaissé, votre serveur transforme le hold en réservation ferme. C'est la seule étape qui rend les sièges définitivement vendus.
ts
const book = await client.holds.book(
eventId,
['A-1', 'A-2'], // seatKeys sélectionnés
session.holdToken,
);
book.bookedSeats; // ['A-1', 'A-2']
book.bookedAt; // Datephp
$book = $client->holds->book(
$eventId,
['A-1', 'A-2'], // seatKeys sélectionnés
$session->holdToken,
);
$book->bookedSeats; // ['A-1', 'A-2']
$book->bookedAt; // DateTimeImmutablebash
curl -X POST https://api.mitoera.com/api/events/EVENT_ID/book \
-u pk_xxxxxxxx:sk_xxxxxxxx \
-H 'Content-Type: application/json' \
-d '{"seatKeys":["A-1","A-2"],"holdToken":"hld_9f2c…"}'Et si l'utilisateur abandonne, libérez explicitement plutôt que d'attendre l'expiration :
ts
await client.holds.release(eventId, ['A-1', 'A-2'], session.holdToken);php
$client->holds->release($eventId, ['A-1', 'A-2'], $session->holdToken);Étape 9 — Vérifier l'état des sièges
Pour contrôler le résultat, demandez la carte des statuts de l'événement :
ts
const map = await client.events.listSeats(eventId);
map.booked(); // ['A-1', 'A-2']
map.available().length; // sièges encore vendables
map.isAvailable('A-3'); // truephp
$map = $client->events->listSeats($eventId);
$map->booked(); // ['A-1', 'A-2']
count($map->available()); // sièges encore vendables
$map->isAvailable('A-3'); // truebash
curl https://api.mitoera.com/api/events/EVENT_ID/seats \
-u pk_xxxxxxxx:sk_xxxxxxxxRécapitulatif
┌ Serveur (clé secrète) ─────────────────────────────────────┐
│ 1. charts.create → dessin → charts.publish │
│ 2. events.create(title, identifier, chartId) │
│ 3. sessions.create(eventId) → sessionToken + holdToken │
└────────────────────────────────────────────────────────────┘
│ sessionToken
▼
┌ Navigateur (clé publique) ─────────────────────────────────┐
│ 4. new SeatingChart({ divId, workspaceKey, event }) │
│ → sélection utilisateur → hold automatique │
│ → onCheckout(seats) │
└────────────────────────────────────────────────────────────┘
│ seatKeys
▼
┌ Serveur (clé secrète) ─────────────────────────────────────┐
│ 5. paiement encaissé │
│ 6. holds.book(eventId, seatKeys, holdToken) │
│ ou holds.release(...) si abandon │
└────────────────────────────────────────────────────────────┘Et ensuite
- Brancher un paiement — le flux complet avec un PSP
- Panier après redirection — ne pas perdre la sélection lors d'un détour par la page de login
- Mode sandbox — rejouer tout ceci sans toucher à la production
- Référence API — tous les endpoints

