Développeurs
Construire sur le réseau
Lancez des travaux sur le réseau mondial, suivez leur avancement et récupérez des résultats vérifiés depuis votre propre code — ou créez une application qui le fait pour d’autres. Une seule API HTTPS pour vos propres scripts et pour les applications qui agissent au nom d’autres personnes. Une clé d’API (dk_…) pour votre code, un jeton d’accès OAuth 2 (do_…) pour une application que quelqu’un a autorisée, des portées qui limitent l’un et l’autre, et des webhooks signés par HMAC pour être prévenu des événements dès qu’ils arrivent.
Les identifiants
dk_…Clé d’API — vos scripts et serveursdo_…Jeton d’accès — une heuredr_…Jeton de rafraîchissement — trente jours, un seul usagewhsec_…Secret de signature des webhooks
Tous s’envoient en Authorization: Bearer …, sauf le secret de webhook, qui ne quitte jamais votre serveur.
Premiers pas
Deux façons d’entrer
Utilisez une clé quand le code est le vôtre et agit pour votre propre compte. Utilisez OAuth quand des personnes se connectent à votre application et la laissent agir pour elles.
Avec une clé d’API
- 1
Créez une clé dans les paramètres développeur. Donnez-lui un nom, uniquement les portées dont elle a besoin, et une date d’expiration si elle sert à quelque chose de temporaire.
Tant que votre adresse e-mail n’est pas confirmée, une clé ne peut porter que les portées de lecture.
- 2
Copiez la clé quand elle s’affiche. Elle n’apparaît qu’une fois : seule une empreinte en est conservée, une clé perdue ne se récupère donc pas, elle se remplace.
- 3
Envoyez-la comme jeton bearer à chaque requête :
shellcurl https://api.thecubefloor.com/v1/me \ -H "Authorization: Bearer dk_…" - 4
Révoquez-la depuis la même page dès qu’elle ne sert plus. La liste indique quand chaque clé a servi pour la dernière fois.
Avec OAuth 2
Le flux par code d’autorisation, avec PKCE (S256) obligatoire à chaque requête. Chaque application est un client confidentiel doté d’un secret.
- 1
Enregistrez l’application dans les paramètres développeur : son nom (les gens le voient quand on leur demande leur accord), ses URI de redirection et les portées qu’elle peut demander. Vous obtenez un
client_idet unclient_secret, le secret affiché une seule fois. Enregistrer une application demande une adresse e-mail confirmée.Les URI de redirection doivent correspondre caractère pour caractère. Ce sont des adresses
https://absolues sans fragment ; lehttp://simple n’est accepté que verslocalhostou une adresse de bouclage, pour le développement et les applications natives. - 2
Générez un
code_verifieraléatoire et envoyez le navigateur de la personne vers/oauth/authorizeavec son SHA-256 commecode_challenge:shell# Un vérificateur : 43 à 128 caractères non réservés. Gardez-le jusqu’à l’échange. CODE_VERIFIER=$(openssl rand -base64 64 | tr -dc 'A-Za-z0-9' | cut -c1-64) CODE_CHALLENGE=$(printf '%s' "$CODE_VERIFIER" | openssl dgst -sha256 -binary \ | openssl base64 -A | tr '+/' '-_' | tr -d '=') https://api.thecubefloor.com/oauth/authorize?response_type=code &client_id=app_… &redirect_uri=https%3A%2F%2Fyour.app%2Fcallback &scope=account%3Aread%20jobs%3Aread &state=… &code_challenge=$CODE_CHALLENGE &code_challenge_method=S256 - 3
Elle voit notre page de consentement sur thecubefloor.com, avec le nom de votre application, ce qu’elle demande et où elle reviendra. Si elle accepte, le navigateur revient sur votre URI de redirection avec
codeet votrestate; si elle refuse, avecerror=access_denied. - 4
Échangez le code, dans la minute et une seule fois, contre des jetons. Authentifiez-vous en HTTP Basic ou avec
client_idetclient_secretdans le formulaire :shellcurl https://api.thecubefloor.com/oauth/token \ -u "$CLIENT_ID:$CLIENT_SECRET" \ -d grant_type=authorization_code \ -d code="$CODE" \ -d redirect_uri=https://your.app/callback \ -d code_verifier="$CODE_VERIFIER" - 5
La réponse contient un jeton d’accès (
do_…, valable une heure) et un jeton de rafraîchissement (dr_…, trente jours). Chaque rafraîchissement consomme le jeton de rafraîchissement et renvoie une nouvelle paire ; présenter un jeton déjà consommé met fin à tous les jetons issus du même accord, car l’un de ses deux détenteurs est un voleur.json · shell{ "access_token": "do_…", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "dr_…", "scope": "account:read jobs:read" } curl https://api.thecubefloor.com/oauth/token \ -u "$CLIENT_ID:$CLIENT_SECRET" \ -d grant_type=refresh_token \ -d refresh_token="$REFRESH_TOKEN" - 6
Quand la personne se déconnecte dans votre application, rendez le jeton (RFC 7009). Un jeton de rafraîchissement met fin à tout l’accord :
shellcurl https://api.thecubefloor.com/oauth/revoke \ -u "$CLIENT_ID:$CLIENT_SECRET" \ -d token="$REFRESH_TOKEN"
Quand quelque chose est refusé
Les erreurs ont la forme {"error": "E_…", "message": "…"} : un code sur lequel votre programme peut s’appuyer et une phrase qu’une personne peut comprendre. 401 signifie que l’identifiant est absent, inconnu, révoqué ou expiré ; 403 E_SCOPE qu’il n’a pas la portée ; 403 E_SESSION_ONLY que l’opération est réservée au site lui-même. Les points d’accès /oauth/ répondent plutôt au format de la RFC 6749.
Portées
Ce qu’une clé ou un jeton peut faire
Une clé ou un jeton ne peut jamais faire plus que son compte lui-même, et un compte dont l’adresse e-mail n’est pas confirmée ne peut accorder que les portées de lecture. Tout ce qui n’est pas listé ici — rechargements, retraits, revendication de machines, connexion du stockage, réglages du compte, gestion des clés et des applications — reste réservé au site.
Webhooks
Soyez prévenu sur le moment
Enregistrez une adresse https:// et les événements qui vous intéressent dans les paramètres développeur. Chaque événement y est envoyé en POST au format JSON, signé avec le secret affiché à la création du webhook.
Événements
| Événement | Envoyé quand |
|---|---|
job.finished | Un travail est terminé et ses résultats sont prêts |
job.failed | Un travail a échoué |
job.undelivered | Un travail a tourné mais ses résultats n’ont pas pu être livrés |
topup.confirmed | Un rechargement a été confirmé |
withdrawal.paid | Un retrait a été payé |
withdrawal.rejected | Un retrait a été refusé |
machine.claimed | Les gains d’une machine reviennent désormais à ce compte |
ping | Un événement de test, envoyé quand vous appuyez sur « Envoyer un test » |
En-têtes
DAIN-Webhook-Id- L’identifiant de l’événement, identique à chaque nouvelle tentative. Servez-vous-en pour écarter un doublon : une livraison a lieu au moins une fois.
DAIN-Webhook-Timestamp- Secondes Unix de cette tentative. Refusez tout ce qui date de plus de cinq minutes.
DAIN-Webhook-Signature- HMAC-SHA256 de l’horodatage, d’un point et du corps brut, avec votre secret
whsec_…pour clé, en hexadécimal.
v1=<hex HMAC-SHA256(secret, timestamp + "." + body)>Ce qui arrive
POST /your/webhook HTTP/1.1
Content-Type: application/json
DAIN-Webhook-Id: evt_…
DAIN-Webhook-Timestamp: 1793351642
DAIN-Webhook-Signature: v1=5f2b…c09e
{
"id": "evt_…",
"type": "job.finished",
"created_at": "2026-10-30T09:14:02Z",
"data": { "job": { "id": "job_…", "state": "done", … } }
}data contient l’objet tel que l’API le montre sur son propre point d’accès : le travail, le rechargement, le retrait (destination masquée) ou la machine. Un travail annulé est de votre fait et n’est pas signalé.
Nouvelles tentatives
- Tentative 1Immédiate
- Tentative 2+1min
- Tentative 3+5min
- Tentative 4+30min
- Tentative 5+2h
- Tentative 6+6h
- Tentative 7+24h
- Désactivé
Toute réponse 2xx y met fin. Sinon, la livraison est retentée après chacun de ces délais — sept tentatives sur environ 33 heures — et si la dernière échoue, le webhook est désactivé. Un test qui obtient une réponse 2xx le réactive. Les redirections ne sont pas suivies.
Les adresses sont vérifiées après résolution DNS, à l’enregistrement et à chaque livraison : rien de privé, de bouclage, de lien local ou de réservé n’est jamais appelé.
Vérifier la signature
Calculez la signature sur le corps exactement tel qu’il est arrivé — avant toute analyse JSON — et comparez en temps constant.
import hashlib, hmac, time
def verify(secret: str, headers, body: bytes) -> bool:
"""body: the request body exactly as it arrived, before json.loads."""
ts = headers["DAIN-Webhook-Timestamp"]
sig = headers.get("DAIN-Webhook-Signature", "")
if abs(time.time() - int(ts)) > 300: # more than five minutes old
return False
mac = hmac.new(secret.encode(), ts.encode() + b"." + body, hashlib.sha256)
return hmac.compare_digest(sig, "v1=" + mac.hexdigest())Référence de l’API
Tous les points d’accès
Lue en direct depuis /v1/openapi.yaml, le contrat OpenAPI 3.1 sur lequel le serveur est testé. Pointez un générateur de clients sur la même adresse.