Documentation API Redax

L'API Redax v1 te permet de connecter Redax à tes outils externes (n8n, Zapier, Make, ton CMS). Tu peux récupérer tes articles, clients et audits, et recevoir des notifications en temps réel via webhooks signés.

Version

v1 (stable)

URL de base

https://www.getredax.com/api/v1

Authentification

Chaque clé API est liée à un client précis (scope client). Elle donne accès uniquement aux ressources de ce client.

  • Crée tes clés depuis /settings/api dans le dashboard
  • La clé complète est affichée une seule fois à la création — conserve-la
  • Seul le préfixe est stocké en clair (redax_live_XXXX…), la clé entière est hashée bcrypt en base

Header attendu :

Authorization: Bearer redax_live_...

Exemple curl :

curl -H "Authorization: Bearer redax_live_..." \
  https://www.getredax.com/api/v1/client

Rate limiting

L'API est limitée à 100 requêtes par minute par clé API (sliding window via Upstash Redis).

Headers retournés quand la limite est dépassée :

HeaderDescription
X-RateLimit-LimitLimite totale (100)
X-RateLimit-RemainingRequêtes restantes dans la fenêtre courante
X-RateLimit-ResetTimestamp Unix de réinitialisation de la fenêtre
Retry-AfterSecondes avant de pouvoir réessayer

Code HTTP retourné : 429 Too Many Requests

Pagination

Les endpoints de liste ( /articles, /audits) supportent la pagination par offset.

ParamètreTypeDéfautDescription
limitinteger20Nombre d'items (1–100)
offsetinteger0Décalage depuis le début

Format de réponse :

{
  "data": [...],
  "pagination": {
    "total": 42,
    "limit": 20,
    "offset": 0,
    "has_more": true
  }
}

Endpoints

GET/api/v1/client

Retourne le client lié à ta clé API.

Exemple curl :

curl -H "Authorization: Bearer redax_live_..." \
  https://www.getredax.com/api/v1/client

Réponse :

{
  "data": {
    "id": "uuid",
    "name": "Mon Client",
    "website_url": "https://example.com",
    "niche_template": "ecommerce",
    "niche_description": "Boutique de vêtements bio",
    "target_audience": "Femmes 25-45 ans sensibles à l'écologie",
    "language": "fr",
    "created_at": "2026-01-15T10:00:00.000Z",
    "updated_at": "2026-03-20T14:30:00.000Z"
  }
}

GET/api/v1/articles

Liste les articles du client, triés par date de création décroissante.

ParamètreTypeDescription
statusstringFiltre par statut : draft, optimizing, completed, error
limitintegerNombre d'articles (1–100, défaut 20)
offsetintegerDécalage (défaut 0)

Exemple curl :

curl -H "Authorization: Bearer redax_live_..." \
  "https://www.getredax.com/api/v1/articles?status=completed&limit=10"

Réponse :

{
  "data": [
    {
      "id": "uuid",
      "title": "Les 10 meilleures pratiques SEO en 2026",
      "meta_description": "Découvre les techniques SEO les plus efficaces...",
      "status": "completed",
      "seo_score": 87,
      "geo_score": 72,
      "word_count": 1850,
      "created_at": "2026-05-10T09:00:00.000Z",
      "updated_at": "2026-05-10T09:45:00.000Z"
    }
  ],
  "pagination": {
    "total": 34,
    "limit": 10,
    "offset": 0,
    "has_more": true
  }
}

GET/api/v1/articles/:id

Détail complet d'un article, incluant content_html et content_markdown.

Exemple curl :

curl -H "Authorization: Bearer redax_live_..." \
  https://www.getredax.com/api/v1/articles/uuid-de-larticle

Réponse :

{
  "data": {
    "id": "uuid",
    "title": "Les 10 meilleures pratiques SEO en 2026",
    "meta_description": "Découvre les techniques SEO...",
    "content_html": "<h1>Les 10 meilleures...</h1><p>...</p>",
    "content_markdown": "# Les 10 meilleures...

...",
    "status": "completed",
    "seo_score": 87,
    "geo_score": 72,
    "word_count": 1850,
    "created_at": "2026-05-10T09:00:00.000Z",
    "updated_at": "2026-05-10T09:45:00.000Z"
  }
}

GET/api/v1/audits

Liste les audits SEO+GEO du client, triés par date de création décroissante.

ParamètreTypeDescription
statusstringFiltre par statut : pending, running, completed, failed
limitintegerNombre d'audits (1–100, défaut 20)
offsetintegerDécalage (défaut 0)

Exemple curl :

curl -H "Authorization: Bearer redax_live_..." \
  "https://www.getredax.com/api/v1/audits?status=completed&limit=5"

Réponse :

{
  "data": [
    {
      "id": "uuid",
      "url": "https://example.com/page",
      "status": "completed",
      "progress": 100,
      "overall_score": 78,
      "technical_score": 82,
      "content_score": 75,
      "geo_score": 68,
      "schema_score": 90,
      "images_score": 71,
      "created_at": "2026-05-15T14:00:00.000Z",
      "completed_at": "2026-05-15T14:02:30.000Z"
    }
  ],
  "pagination": {
    "total": 12,
    "limit": 5,
    "offset": 0,
    "has_more": true
  }
}

GET/api/v1/audits/:id

Détail complet d'un audit avec full_report (rapport JSON structuré) et cwv_data (Core Web Vitals).

Exemple curl :

curl -H "Authorization: Bearer redax_live_..." \
  https://www.getredax.com/api/v1/audits/uuid-de-laudit

Réponse :

{
  "data": {
    "id": "uuid",
    "url": "https://example.com/page",
    "status": "completed",
    "progress": 100,
    "overall_score": 78,
    "technical_score": 82,
    "content_score": 75,
    "geo_score": 68,
    "schema_score": 90,
    "images_score": 71,
    "full_report": { ... },
    "cwv_data": {
      "lcp": 2.1,
      "fid": 45,
      "cls": 0.08
    },
    "created_at": "2026-05-15T14:00:00.000Z",
    "completed_at": "2026-05-15T14:02:30.000Z"
  }
}

GET/api/v1/audits/:id/issues

Issues détectées dans un audit, triées par sévérité (critical → high → medium → low).

Exemple curl :

curl -H "Authorization: Bearer redax_live_..." \
  https://www.getredax.com/api/v1/audits/uuid-de-laudit/issues

Réponse :

{
  "data": [
    {
      "id": "uuid",
      "issue_code": "missing_h1",
      "severity": "critical",
      "category": "technical",
      "title": "Balise H1 manquante",
      "description": "La page ne contient pas de balise H1.",
      "fix": "Ajoute une balise H1 avec le mot-clé principal.",
      "estimated_impact": "Amélioration du score technique de +8 points",
      "status": "open",
      "created_at": "2026-05-15T14:02:30.000Z"
    }
  ]
}

GET/api/v1/campaigns

Liste les campagnes éditoriales du client, triées par date de création décroissante.

ParamètreTypeDescription
statusstringFiltre par statut : draft, running, paused, completed, cancelled
limitintegerNombre d'éléments (1–100, défaut 20)
offsetintegerDécalage (défaut 0)

Exemple curl :

curl -H "Authorization: Bearer redax_live_xxx" \
  "https://www.getredax.com/api/v1/campaigns?status=running&limit=10"

Réponse :

{
  "data": [
    {
      "id": "uuid",
      "name": "Test email completed",
      "status": "completed",
      "cadence_days": 1,
      "scheduled_time": "09:00:00",
      "timezone": "Europe/Paris",
      "start_date": "2026-05-18",
      "total_articles": 1,
      "generated_count": 1,
      "failed_count": 0,
      "created_at": "2026-05-18T16:14:00Z",
      "completed_at": "2026-05-18T16:21:00Z",
      "paused_at": null
    }
  ],
  "pagination": { "limit": 10, "offset": 0, "count": 1 }
}

GET/api/v1/campaigns/:id

Détail d'une campagne incluant la liste de ses articles planifiés dans scheduled_articles.

Exemple curl :

curl -H "Authorization: Bearer redax_live_xxx" \
  "https://www.getredax.com/api/v1/campaigns/uuid"

Réponse :

{
  "id": "uuid",
  "name": "Test email completed",
  "status": "completed",
  "cadence_days": 1,
  "scheduled_time": "09:00:00",
  "timezone": "Europe/Paris",
  "start_date": "2026-05-18",
  "total_articles": 1,
  "generated_count": 1,
  "failed_count": 0,
  "created_at": "2026-05-18T16:14:00Z",
  "completed_at": "2026-05-18T16:21:00Z",
  "paused_at": null,
  "scheduled_articles": [
    {
      "id": "uuid",
      "position": 1,
      "brief": "Le ROI des robots aspirateurs...",
      "focus_keyword": "robots aspirateurs industriels",
      "scheduled_for": "2026-05-18T16:15:00Z",
      "status": "generated",
      "error_message": null,
      "retry_count": 0,
      "article_id": "uuid",
      "generated_at": "2026-05-18T16:21:00Z"
    }
  ]
}

Statuts possibles pour scheduled_articles[].status :

StatutDescription
pendingEn attente du prochain cron (toutes les 5 min)
generatingGénération en cours via Claude
generatedArticle créé avec succès — article_id rempli
failedÉchec — voir error_message
cancelled / skippedSuite à une annulation manuelle de la campagne

Pour récupérer l'article complet, appelle GET /api/v1/articles/{article_id} avec le article_id retourné.

Webhooks

Configuration

Configure tes webhooks depuis /settings/webhooks dans le dashboard. Pour chaque webhook tu définis :

  • Une URL HTTPS qui recevra les POST
  • La liste des events à écouter
  • Un secret partagé utilisé pour signer chaque payload HMAC SHA256

Le secret complet est affiché une seule fois à la création — conserve-le.

Events disponibles

EventQuandData
article.generatedArticle généré avec succèsObjet article (id, title, scores, word_count…)
audit.completedAudit SEO+GEO terminé (status = completed)Objet audit (id, url, scores…)
test.pingDéclenché manuellement depuis l'UI{ message, timestamp }

Format du payload

Chaque payload reçu a cette enveloppe :

{
  "event": "article.generated",
  "created_at": "2026-05-18T11:30:00.000Z",
  "delivery_id": "uuid-pour-idempotency",
  "data": {
    // Données spécifiques à l'event
  }
}

Utilise delivery_id pour l'idempotency — chaque tentative a un ID unique.

Headers envoyés

HeaderValeurDescription
Content-Typeapplication/jsonToujours présent
User-AgentRedax-Webhook/1.0
X-Redax-Eventarticle.generatedNom de l'event
X-Redax-Delivery-Iduuid v4Unique par tentative — utilise-le pour l'idempotency
X-Redax-Signaturesha256={hex}HMAC SHA256 du body brut

Vérification de la signature

Vérifie toujours la signature avant de traiter un payload. Utilise le body brut (raw body, pas le JSON parsé).

Exemple Node.js :

import crypto from "crypto"

function verifyRedaxSignature(rawBody, signatureHeader, secret) {
  const expected = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex")

  return crypto.timingSafeEqual(
    Buffer.from(signatureHeader),
    Buffer.from(expected)
  )
}

// Express
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  const sig = req.headers["x-redax-signature"]
  if (!verifyRedaxSignature(req.body, sig, process.env.REDAX_WEBHOOK_SECRET)) {
    return res.status(401).send("Invalid signature")
  }
  const payload = JSON.parse(req.body.toString())
  // traite payload.event...
  res.status(200).send("OK")
})

En n8n :

// Code node (JavaScript)
const rawBody = $input.first().json.rawBody
const signature = $input.first().headers["x-redax-signature"]
const secret = "whsec_..."

const expected = "sha256=" + require("crypto")
  .createHmac("sha256", secret)
  .update(rawBody)
  .digest("hex")

if (signature !== expected) throw new Error("Invalid signature")
return $input.all()

Retry policy

  • 2 tentatives max (1 essai initial + 1 retry)
  • Backoff : 1 seconde entre les tentatives
  • Timeout par tentative : 3 secondes
  • Si 10 échecs consécutifs, le webhook est désactivé automatiquement — tu peux le réactiver depuis /settings/webhooks
  • Toutes les tentatives sont visibles dans l'onglet Deliveries

Codes erreur

Les erreurs retournent toujours un JSON { "error": "code_machine" }.

Code HTTPError machineCause
401missing_or_invalid_auth_headerPas de header Authorization Bearer
401invalid_api_keyClé invalide, révoquée ou inexistante
400invalid_query_paramsQuery params invalides (limit hors 1–100, etc.)
400invalid_bodyBody JSON invalide ou champs manquants
404not_foundResource introuvable ou hors scope du client
429rate_limit_exceeded100 req/min dépassé — attends Retry-After secondes
500internal_errorErreur serveur — à signaler à hello@axyos-agency.com