Documentation API

Encodage programmatique — réservé aux abonnés Ultra. Créez une clé sur Compte → Clés API, puis insérez-la directement dans les URLs des endpoints ci-dessous.

Limites par plan

PlanMax par fichierAccès APIMultipart requis ?
Free 5 Ko
Pro 100 Mo Non (PUT unique suffit)
Ultra 300 Mo Oui Fichiers >100 Mo doivent passer en multipart

L'edge Cloudflare limite un body de requête à 100 Mo. Les fichiers plus gros doivent être découpés en parts de 50 Mo et passer par les endpoints multipart ci-dessous.

Upload PUT unique (≤100 Mo)

POST https://webhook.binaryphp.com/upload/<api_key>
  X-BPHP-Filename: plugin.php          # requis, extension .php ou .zip
  X-BPHP-Domain:   app.example.com,*.example.com
  X-BPHP-Mac:      aa:bb:cc:dd:ee:ff   # facultatif
  X-BPHP-Expire:   2027-12-31          # facultatif
  X-BPHP-Webhook:  https://you.example.com/wh    # facultatif, pour notification asynchrone
  <binaire du fichier en request body>

→ 200 {
    "job_id":       "...",
    "download_url": "https://...presigned R2 URL...",
    "expires_at":   "2026-05-09T...",
    "size":         12345,
    "license":      { "domains": [...], ... }
  }

curl en une ligne :

curl -X POST https://webhook.binaryphp.com/upload/$API_KEY \
  -H "X-BPHP-Filename: plugin.php" \
  -H "X-BPHP-Domain: app.example.com" \
  --data-binary @plugin.php

Upload multipart (taille libre, >100 Mo obligatoire)

Trois étapes : init → PUT individuel pour chaque part → complete.

1. Init (initialisation)

POST https://webhook.binaryphp.com/upload/<api_key>/init
  X-BPHP-Filename:   bigplugin.zip
  X-BPHP-Total-Size: 200000000

→ 200 {
    "job_id":     "...",
    "upload_id":  "...",                         # ID opaque R2 multipart
    "r2_key":     "uploads/<job_id>.zip",
    "part_size":  52428800,                      # recommandé 50 Mo / part
    "part_count": 4,
    "max_part_size": 104857600,                  # limite dure 100 Mo
    "parts": [
      { "part_no": 1, "upload_url": "https://...presigned PUT..." },
      { "part_no": 2, "upload_url": "..." },
      { "part_no": 3, "upload_url": "..." },
      { "part_no": 4, "upload_url": "..." }
    ]
  }

2. PUT pour chaque upload_url

Ces URLs presigned visent directement R2 et ne consomment pas la bande passante du Worker. Le header ETag de chaque réponse PUT doit être collecté et renvoyé à l'étape complete :

PUT <upload_url>
  <lire part_size octets à l'offset (part_no-1)*part_size du fichier>

← 200 OK
  ETag: "abc123def456..."

Chaque part doit faire ≥5 Mo (sauf la dernière qui peut être plus petite) et ≤100 Mo.

3. Complete (finalisation)

POST https://webhook.binaryphp.com/upload/<api_key>/complete
Content-Type: application/json

{
  "upload_id": "...",
  "r2_key":    "uploads/<job_id>.zip",
  "filename":  "bigplugin.zip",
  "parts": [
    { "part_no": 1, "etag": "\"abc...\"" },
    { "part_no": 2, "etag": "\"def...\"" },
    { "part_no": 3, "etag": "\"ghi...\"" },
    { "part_no": 4, "etag": "\"jkl...\"" }
  ],
  "domain":   "app.example.com",
  "mac":      "",
  "expire":   "2027-12-31",
  "plugin":   "",
  "webhook":  ""
}

→ 200 { "job_id", "download_url", "expires_at", "size", "license" }

Abort (facultatif)

Si l'upload d'un part échoue en cours de route, appelez /upload/<api_key>/abort avec { upload_id, r2_key } pour éviter que les parts restants ne soient facturés sur R2.

Notifications Webhook

Définissez X-BPHP-Webhook (ou "webhook" dans le body de complete) pour recevoir des événements encode.completed. Les notifications partent d'IPs Cloudflare edge, sans révéler notre IP d'hôte. Le body est signé en HMAC-SHA256 avec votre clé API comme secret partagé :

POST <votre URL webhook>
  X-BinaryPHP-Signature: t=1736208000,v1=<hex>
  X-BinaryPHP-Event:     encode.completed
  Content-Type:          application/json

{
  "event":        "encode.completed",
  "job_id":       "...",
  "download_url": "...",
  "expires_at":   "...",
  "size":         12345,
  "license":      { ... }
}

Exemple de vérification (PHP) :

$sig_h = $_SERVER['HTTP_X_BINARYPHP_SIGNATURE'] ?? '';
[$tpart, $vpart] = array_pad(explode(',', $sig_h, 2), 2, '');
$ts  = (int) substr($tpart, 2);
$got = substr($vpart, 3);
if (abs(time() - $ts) > 300) http_response_code(401);
$body = file_get_contents('php://input');
$expected = hash_hmac('sha256', "$ts.$body", $YOUR_API_KEY);
if (!hash_equals($expected, $got)) http_response_code(401);

Clients prêts à l'emploi

Erreurs courantes

CodeSignificationQue faire
401Clé erronée ou révoquée Recréez-en une dans « Compte → Clés API »
402Plan ne supporte pas cette opération (ex. Free + upload zip) Mettez votre plan à niveau
413Fichier / Content-Length dépasse la limite du plan Passez en multipart, ou Pro→Ultra (300 Mo)
400Champ manquant ou format incorrect (filename, parts, etc.) Consultez le body de la réponse, il indique le champ manquant
502Opération multipart R2 échouée Réessayez init ; R2 échoue parfois (<1%)