Aller au contenu
公開 API · 無料

YA-Planning API ドキュメント

時間割の生成と閲覧を統合し、学校の設定を管理し、リアルタイムでイベントを受信できます。完全なリファレンス、サンプル、サンドボックス。

はじめに

API は REST 形式、JSON、バージョン管理されています。すべての業務リソースはプレフィックス /api/v1/pub/v1 の下にあります。公開デモのエンドポイントは /api/v1/public/api-demo の下にあります。

  • Base URL:https://votre-domaine/api/v1/pub/v1
  • 形式:リクエストとレスポンスは application/json(ICS/PDF エクスポートを除く)。
  • バージョニング:バージョンはパスに含まれます(/v1)。後方互換のある追加ではバージョンは変わりません。
  • CORS:公開 API はサードパーティのブラウザアプリケーションに開かれています(Cookie なし)。

認証

各リクエストは、2つのヘッダーのいずれかに API キーを含めます:

X-API-Key: yap_live_xxxxxxxxxxxxxxxxxxxx
# ou
Authorization: Bearer yap_live_xxxxxxxxxxxxxxxxxxxx

1つのキーを複数の学校に対して許可できます(エンタープライズキー)。その場合は X-Etablissement-Id ヘッダーで対象を指定してください。許可された学校が1つだけの場合は自動的に判別されます。キーはスコープ付きで コンソール から作成します。

環境とサンドボックス

キーのプレフィックスで区別される2つの環境:

  • yap_live_… — 本番:実際のデータ。生成は週間クォータを消費します。
  • yap_test_… — サンドボックス:読み取りはデモデータのセットを返し(実データは決して返しません)、生成はクォータから消費されず、設定の書き込みは拒否されます(SANDBOX_READONLY)。リスクなく開発するのに最適です。

スコープ

各キーはスコープのサブセットを持ちます。必要なスコープが不足している場合、エンドポイントは拒否します(403 INSUFFICIENT_SCOPE)。

config:readサイクル、クラス、科目、教員、コマ、授業時数を読み取ります。
config:write学校の設定を作成 / 変更 / 削除します。
timetables:readジョブの一覧表示、結果と公開済み時間割の読み取り、エクスポート。
timetables:write生成の実行と時間割の公開。
webhooks:manageWebhook エンドポイントの作成、一覧表示、削除。
establishments:manage自分の学校の作成と一覧表示(アカウントレベル、X-Etablissement-Id なし)。

レート制限とクォータ

各キーにはレート制限があります(デフォルト 60 req/min)。レスポンスには次が含まれます:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 1783919311   # epoch (s) de réinitialisation

超過すると Retry-After ヘッダー付きで 429 RATE_LIMITED を返します。時間割の生成はさらにプランの週間クォータの対象となります(/me で確認可能)。

API のすべてのレスポンスには X-Request-Id ヘッダー(相関 ID)も含まれます — 障害時にはサポートへお伝えください。注:レート集計は現在インスタンスごとに適用されています。複数インスタンスのデプロイでは、実効的な制限が表示値の倍数になる場合があります。

エラー

サポート用の requestId を含む、統一されたエラーエンベロープ:

{ "error": "INSUFFICIENT_SCOPE", "message": "Scope requis : config:write.",
  "requestId": "6181762d-…", "requiredScope": "config:write" }
コードerror原因
400BAD_REQUESTパラメータが不足または無効です。
401UNAUTHORIZED / INVALID_API_KEYキーが存在しない、無効、または失効しています。
403INSUFFICIENT_SCOPEキーに必要なスコープがありません。
403ETABLISSEMENT_NOT_GRANTEDキーは要求された学校に対して許可されていません。
403SANDBOX_READONLYサンドボックスキーでは書き込みできません(読み取り専用)。
402PLAN_UPGRADE_REQUIRED有料プラン専用の機能です(例:iCal エクスポート)。
404NOT_FOUNDリソースが存在しないか、貴校の範囲外です。
409WORKFLOW_ERRORワークフローの遷移ができません(例:下書きの公開)。
429RATE_LIMITEDレート超過 — Retry-After ヘッダーの後に再試行してください。

その場でテスト — 登録不要

公開デモのエンドポイント(キー不要)。

OpenAPI をダウンロード

Postman:「Import」→「Link」→ /q/openapi?format=json を貼り付け。

リファレンス — アカウントとイントロスペクション

GET/me

現在のキーの詳細:環境、対象の学校、付与されたスコープ、残りの生成クォータ。スコープ不要。

レスポンス
{
  "environment": "LIVE",
  "etablissementId": "61a9…8cb",
  "scopes": ["config:read", "timetables:write"],
  "entitlements": {
    "plan": "PRO",
    "generationsRestantes": -1,
    "resetLe": "2026-07-14T00:00:00Z",
    "maxClassesExport": -1
  }
}
GET/me/etablissement

対象の学校の公開プロフィール:名称、略称、都市、国、種類、ウェブサイト。スコープ不要。

レスポンス
{"id":"…","nom":"Groupe Scolaire Les Palmiers","slug":"gs-palmiers","sigle":"GSP","ville":"Abidjan","pays":"CI","type":"PRIVE","siteWeb":"https://…"}
GET/me/usage

現在のキーの最近の使用状況(1日あたりの呼び出しとエラー)。スコープ不要。

パラメータ:
  • days — 日数のウィンドウ(デフォルト30、最大90)
レスポンス
{"apiKeyId":"…","days":30,"daily":[{"day":"2026-07-12","calls":128,"errors":3}]}

リファレンス — アカウント — 学校

アカウントレベルのプロビジョニング:X-Etablissement-Id ヘッダーなしで自分の学校を作成します(/account パスは学校に紐付きません)。スコープ establishments:manage。作成時、呼び出し元のキーは新しい学校に対して自動的に ACTIVE グラントを受け取ります — その後は X-Etablissement-Id を使って設定・生成してください。

POST/account/etablissementsestablishments:manage

学校を作成します(開発者バケット、アカウントの上限の対象)。

ボディ
{"nom":"Groupe Scolaire Les Palmiers","type":"PRIVE_LAIC","pays":"CI"}
レスポンス
{"id":"…","nom":"Groupe Scolaire Les Palmiers","slug":"gs-les-palmiers","pays":"CI","type":"PRIVE_LAIC"}
GET/account/etablissementsestablishments:manage

作成した学校を一覧表示します。

レスポンス
[{"id":"…","nom":"…","slug":"…","pays":"CI","type":"PRIVE_LAIC"}]

リファレンス — 設定

学校の教育構造。読み取り:スコープ config:read。書き込み:スコープ config:write(サンドボックスでは禁止)。新規作成した学校には、すでに「メインサイクル」が含まれています。

GET/cyclesconfig:read

サイクルの一覧。

レスポンス
[{"id":"…","libelle":"Cycle principal","ordre":0}]
POST/cyclesconfig:write

サイクルを作成。

ボディ
{"libelle":"Second cycle","ordre":1}
DELETE/cycles/{id}config:write

サイクルを削除。

GET/niveauxconfig:read

クラス / 学年の一覧。

レスポンス
[{"id":"…","libelle":"6ème 1","cycleId":"…","effectif":42,"ordre":1}]
POST/niveauxconfig:write

クラスを作成。

ボディ
{"libelle":"6ème 3","cycleId":"<uuid-cycle>","effectif":40,"ordre":3}
PUT/niveaux/{id}config:write

クラスを変更(部分フィールド)。

DELETE/niveaux/{id}config:write

クラスを削除。

GET/disciplinesconfig:read

科目の一覧。

レスポンス
[{"id":"…","libelle":"Mathématiques","code":"MATH","couleur":"#6C5CE7","ordre":1}]
POST/disciplinesconfig:write

科目を作成。

ボディ
{"libelle":"Physique-Chimie","code":"PC","couleur":"#00B894","ordre":5}
PUT/disciplines/{id}config:write

科目を変更。

DELETE/disciplines/{id}config:write

科目を削除。

GET/professeursconfig:read

教員の一覧。

レスポンス
[{"id":"…","nom":"Koné","prenoms":"Awa","matricule":"P-0142","email":"…","telephone":"…","nombreHeureAutorise":18,"statut":"TITULAIRE","actif":true}]
POST/professeursconfig:write

教員を作成。

ボディ
{"nom":"Diarra","prenoms":"Sékou","matricule":"P-0210","email":"s.diarra@ecole.ci","nombreHeureAutorise":18,"statut":"VACATAIRE","actif":true}
PUT/professeurs/{id}config:write

教員を変更。

DELETE/professeurs/{id}config:write

教員を削除。

GET/horairesconfig:read

グリッドのコマ。

レスポンス
[{"id":"…","jour":"MONDAY","heureDebut":"08:00","heureFin":"09:00","estPause":false,"libelle":null}]
POST/horairesconfig:write

コマを作成(曜日、HH:mm)。

ボディ
{"jour":"MONDAY","heureDebut":"08:00","heureFin":"09:00","estPause":false,"libelle":"M1"}
DELETE/horaires/{id}config:write

コマを削除。

GET/volumesconfig:read

授業時数(科目 × サイクル)。

レスポンス
[{"id":"…","cycleId":"…","disciplineId":"…","nombreHeuresObligatoire":4,"minHeuresConsecutives":1,"maxHeuresConsecutives":2}]
POST/volumesconfig:write

授業時数を作成。

ボディ
{"cycleId":"<uuid>","disciplineId":"<uuid>","nombreHeuresObligatoire":4,"minHeuresConsecutives":1,"maxHeuresConsecutives":2}
DELETE/volumes/{id}config:write

授業時数を削除。

リファレンス — 時間割

非同期の生成(ソルバーはバックグラウンドで実行 — ステータスを問い合わせてください)、公開、閲覧。サンドボックスでは、生成はデモセットを使用し、クォータから消費されません。

POST/timetables/generatetimetables:write

生成を実行します。202 と問い合わせ用の jobId を返します。LIVE では週間クォータを消費します。任意の Idempotency-Key ヘッダー:同じ識別子は、生成を再実行する代わりに、記憶されたレスポンスを再送します(レスポンスに Idempotency-Replayed: true が付きます)。

パラメータ:
  • Idempotency-Key — ヘッダー(任意)— LIVE 側の冪等性キー
ボディ
{"durationMinutes": 5}
レスポンス
{"jobId":"…","status":"SOLVING_SCHEDULED"}
GET/timetables/jobstimetables:read

ジョブのページネーション付き一覧。

パラメータ:
  • page — ページのインデックス(デフォルト0)
  • size — サイズ(デフォルト25、最大100)
レスポンス
{"items":[{"jobId":"…","name":"…","status":"SOLVING_ENDED","workflowStatus":"BROUILLON","feasible":true,"hardScore":0,"softScore":-42,"createdAt":"…"}],"total":7,"page":0,"size":25}
GET/timetables/jobs/{jobId}timetables:read

ジョブのステータス。

GET/timetables/jobs/{jobId}/resulttimetables:read

結果:授業の一覧(status = SOLVING_ENDED になったら)。

レスポンス
{"jobId":"…","status":"SOLVING_ENDED","feasible":true,"lessons":[{"id":"1","matiere":"Maths","niveau":"6ème 1","professeur":"M. Koné","jour":"MONDAY","debut":"08:00:00","fin":"09:00:00","couleur":"#6C5CE7","niveauOrdre":1,"verrouille":false}]}
POST/timetables/jobs/{jobId}/publishtimetables:write

時間割を公開します(ワークフロー → PUBLIE)。webhook イベント timetable.published を発火します。

GET/timetables/published/latesttimetables:read

学校の最新の公開済み時間割。

GET/timetables/published/{jobId}/classestimetables:read

公開済み時間割に含まれるクラスの名称。

レスポンス
{"classes":["6ème 1","6ème 2","5ème 1"]}
GET/timetables/published/{jobId}/classe/{niveau}timetables:read

公開済み時間割の1クラスの授業。

GET/timetables/jobs/{jobId}/export.icstimetables:read

iCalendar エクスポート(text/calendar)。Pro プラン専用 → それ以外は 402。

パラメータ:
  • niveau — クラスで絞り込み
  • professeur — 教員で絞り込み
GET/timetables/jobs/{jobId}/export.pdftimetables:read

PDF エクスポート(application/pdf)— 全体、クラス別、または教員別。

パラメータ:
  • mode — all | class | teacher
  • niveau — mode=class の場合は必須
  • professeur — mode=teacher の場合は必須

リファレンス — Webhook

署名付きイベントを受信します。スコープ webhooks:manage。シークレットは作成時(またはローテーション後)のみ返されます。イベント:timetable.job.completed、timetable.job.failed、timetable.published、webhook.test。各配信は署名され(HMAC-SHA256)、失敗時は最大5回まで再送されます。URL は SSRF に対して検証されます(内部・プライベートの宛先は拒否)。

GET/webhookswebhooks:manage

エンドポイントの一覧。

POST/webhookswebhooks:manage

エンドポイントを作成します。署名シークレットを返します(保管してください)。

ボディ
{"url":"https://exemple.com/webhooks/yap","events":["timetable.published","timetable.job.completed"]}
レスポンス
{"endpoint":{"id":"…","url":"…","events":["timetable.published"],"active":true},"secret":"whsec_…"}
DELETE/webhooks/{id}webhooks:manage

エンドポイントを削除。

GET/webhooks/{id}/deliverieswebhooks:manage

配信ログ(ステータス、HTTP コード、試行回数)。

POST/webhooks/{id}/rotatewebhooks:manage

署名シークレットを再生成します(1回のみ返されます)。

レスポンス
{"endpoint":{"id":"…","url":"…"},"secret":"whsec_…"}
POST/webhooks/{id}/testwebhooks:manage

エンドポイントに webhook.test イベントを送信します(202 + status queued)。

POST/webhooks/deliveries/{deliveryId}/replaywebhooks:manage

過去の配信を再送します(202 + status queued)。

リファレンス — デモ(公開、キー不要)

レスポンスの形式を確認するための、認証不要の公開エンドポイント。

GET/api/v1/public/api-demo/preview

デモ学校のプレビュー(サイクル、クラス、科目、教員、コマ)。

GET/api/v1/public/api-demo/sample-timetable

授業の例(生成された時間割の形式)。

Webhook — 署名の検証

各配信は、ヘッダー X-Webhook-Event、X-Webhook-Timestamp、X-Webhook-Signature = HMAC-SHA256(timestamp + "." + body, secret) を含む POST JSON です。リプレイを防ぐため、署名とタイムスタンプの新しさ(5分以内)を検証してください。イベント:timetable.published、timetable.job.completed、timetable.job.failed、webhook.test。

POST https://votre-app/webhook
X-Webhook-Event: timetable.published
X-Webhook-Timestamp: 1712345678
X-Webhook-Signature: 9f86d081…

{ "event":"timetable.published", "jobId":"…", "etablissementId":"…", "occurredAt":"…" }
import crypto from "crypto";

// Express — vérifier la signature d'un webhook YA-Planning
app.post("/webhooks/yap", express.raw({ type: "*/*" }), (req, res) => {
  const ts  = req.header("X-Webhook-Timestamp");
  const sig = req.header("X-Webhook-Signature");
  const body = req.body.toString("utf8");

  const expected = crypto.createHmac("sha256", process.env.YAP_WEBHOOK_SECRET)
    .update(`${ts}.${body}`).digest("hex");

  // fraîcheur (anti-rejeu) : < 5 min
  const fresh = Math.abs(Date.now()/1000 - Number(ts)) < 300;
  if (!fresh || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)))
    return res.sendStatus(400);

  const event = JSON.parse(body); // { event, jobId, etablissementId, occurredAt }
  res.sendStatus(200);
});

コード例

# Vérifier ses droits
curl https://votre-domaine/api/v1/pub/v1/me \
  -H "X-API-Key: yap_live_xxxxxxxxxxxx"

# Générer un EDT puis suivre le job
JOB=$(curl -s -X POST .../api/v1/pub/v1/timetables/generate \
  -H "X-API-Key: yap_live_xxxx" -H "Content-Type: application/json" \
  -d '{"durationMinutes":5}' | jq -r .jobId)

curl .../api/v1/pub/v1/timetables/jobs/$JOB \
  -H "X-API-Key: yap_live_xxxx"

バージョンと非推奨化

API はパスでバージョン管理されています(/api/v1/pub/v1/…)。フィールドやエンドポイントは後方互換の形で追加します。これらの追加は破壊的変更ではないため、寛容にコーディングしてください(未知のフィールドは無視する)。破壊的変更が生じる場合は、新しいメジャーバージョンとして、最低90日前の予告を行い、Deprecation レスポンスヘッダーと以下の変更履歴で通知します。

変更履歴
  • 2026-07 — 開発者アカウントとダッシュボード。アカウントレベルのプロビジョニング(POST /account/etablissements、スコープ establishments:manage)。/cycles エンドポイント。PDF エクスポート mode=teacher。
  • 2026-07 — 生成時の Idempotency-Key。/me/etablissement、/me/usage エンドポイント。Webhook のローテーション / テスト / 再送。timetable.job.failed イベント。X-Request-Id ヘッダー。設定一覧のページネーション。キーの有効期限と IP 制限。Webhook URL の SSRF 対策バリデーション。
  • 2026-06 — 公開 API v1 のリリース:スコープ付きキー、設定、時間割の生成と公開、署名付き Webhook、サンドボックス、クォータヘッダー。

統合の準備はできましたか?

30秒でサンドボックスキーを作成し、最初の呼び出しを行いましょう。

API コンソールを開く