Aller au contenu

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 serveurs
  • do_…Jeton d’accès — une heure
  • dr_…Jeton de rafraîchissement — trente jours, un seul usage
  • whsec_…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. 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. 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. 3

    Envoyez-la comme jeton bearer à chaque requête :

    shell
    curl https://api.thecubefloor.com/v1/me \
      -H "Authorization: Bearer dk_…"
  4. 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. 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_id et un client_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 ; le http:// simple n’est accepté que vers localhost ou une adresse de bouclage, pour le développement et les applications natives.

  2. 2

    Générez un code_verifier aléatoire et envoyez le navigateur de la personne vers /oauth/authorize avec son SHA-256 comme code_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. 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 code et votre state ; si elle refuse, avec error=access_denied.

  4. 4

    Échangez le code, dans la minute et une seule fois, contre des jetons. Authentifiez-vous en HTTP Basic ou avec client_id et client_secret dans le formulaire :

    shell
    curl 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. 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. 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 :

    shell
    curl 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.

Les portées et les points d’accès que chacune ouvre
PortéeCe qu’elle permetPoints d’accès
account:read

Lire votre compte

Les informations de votre compte et vos soldes.

  • GET /v1/me
jobs:read

Voir vos travaux

Les travaux que vous avez lancés, leur avancement et leurs résultats.

  • GET /v1/jobs
  • GET /v1/jobs/{id}
jobs:write

Lancer et annuler des travaux

Lancer, estimer et annuler des travaux, en dépensant le crédit de votre compte.

  • POST /v1/jobs
  • POST /v1/jobs/estimate
  • POST /v1/jobs/{id}/cancel
machines:read

Voir vos machines

Vos machines, les commandes qui leur sont envoyées et ce qu’elles ont gagné.

  • GET /v1/me/machines
  • GET /v1/me/earnings
  • GET /v1/me/machines/{handle}/control
machines:write

Piloter vos machines

Redémarrer, éteindre ou changer l’adresse de vos machines.

  • POST /v1/me/machines/{handle}/control
money:read

Voir vos rechargements et retraits

Vos rechargements et vos retraits, et où en est chacun.

  • GET /v1/me/topups
  • GET /v1/me/withdrawals
drive:read

Voir votre stockage connecté

Si votre propre stockage est connecté, et un résumé de son contenu.

  • GET /v1/drive/google
  • GET /v1/storage/mine
webhooks:write

Gérer vos webhooks

Ajouter, tester et supprimer les adresses auxquelles vos événements sont envoyés.

  • /v1/me/webhooks …

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

Types d’événements et leur signification
ÉvénementEnvoyé quand
job.finishedUn travail est terminé et ses résultats sont prêts
job.failedUn travail a échoué
job.undeliveredUn travail a tourné mais ses résultats n’ont pas pu être livrés
topup.confirmedUn rechargement a été confirmé
withdrawal.paidUn retrait a été payé
withdrawal.rejectedUn retrait a été refusé
machine.claimedLes gains d’une machine reviennent désormais à ce compte
pingUn é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

http
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

  1. Tentative 1Immédiate
  2. Tentative 2+1min
  3. Tentative 3+5min
  4. Tentative 4+30min
  5. Tentative 5+2h
  6. Tentative 6+6h
  7. Tentative 7+24h
  8. 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.

python
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.