Documentation de l'API SecuProbe
Automatisez le scan de sécurité dans votre pipeline CI/CD avec l'API REST SecuProbe. Un compte Free comprend 10 scans par API ; l'export SARIF, le commentaire de pull request et les webhooks de déploiement commencent au plan Starter. Obtenir une clé d'API →
Authentification
Toutes les requêtes de l'API v1 exigent votre clé d'API dans l'en-tête Authorization, sous forme de jeton Bearer. Les clés d'API commencent par sp_live_.
curl https://secuprobe.io/api/v1/scans \
-H "Authorization: Bearer sp_live_YOUR_API_KEY"Générez vos clés d'API dans Tableau de bord → Paramètres → API. Gardez-les secrètes : ne les ajoutez pas au dépôt de code, et stockez-les comme secrets de CI/CD.
Limites de fréquence
Les limites de fréquence s'appliquent par clé d'API et par minute. Les requêtes au-delà de la limite renvoient 429 Too Many Requests.
| Offre | Requêtes / minute | Scans par API |
|---|---|---|
| Free | 10 | 10 (essai) |
| Starter | 30 | Illimités |
| Pro | 60 | Illimités |
| Business | 120 | Illimités |
| Enterprise | 200 | Illimités |
En-têtes de limite : X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (horodatage Unix).
Points d'entrée
URL de base : https://secuprobe.io/api/v1
/api/v1/scanspérimètre : scans:createLance un scan de sécurité. L'URL doit viser un domaine validé de votre compte : une clé d'API ne peut rien scanner d'autre. La requête répond immédiatement avec un identifiant de scan ; interrogez GET /scans/:id pour connaître l'état.
curl -X POST https://secuprobe.io/api/v1/scans \
-H "Authorization: Bearer sp_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "url": "https://your-domain.com" }'{
"scanId": "550e8400-e29b-41d4-a716-446655440000",
"status": "queued",
"estimatedDuration": 120,
"resultsUrl": "https://secuprobe.io/api/v1/scans/550e8400-e29b-41d4-a716-446655440000",
"reportUrl": "https://secuprobe.io/scan/550e8400-e29b-41d4-a716-446655440000"
}/api/v1/scans/{id}périmètre : scans:readRenvoie l'état et le résumé d'un scan. Interrogez jusqu'à ce que l'état soit 'completed' ou 'failed'.
curl https://secuprobe.io/api/v1/scans/SCAN_ID \
-H "Authorization: Bearer sp_live_YOUR_API_KEY"{
"scanId": "550e8400-...",
"url": "https://your-domain.com",
"status": "completed",
"secuScore": 78,
"vulnerabilitiesCount": {
"critical": 1,
"high": 3,
"medium": 5,
"low": 8,
"info": 12
},
"completedAt": "2026-03-10T12:00:00Z",
"reportUrl": "https://secuprobe.io/scan/550e8400-..."
}/api/v1/scans/{id}/vulnerabilitiespérimètre : scans:readListe toutes les failles trouvées par un scan, avec leur description et leur guide de correction.
curl https://secuprobe.io/api/v1/scans/SCAN_ID/vulnerabilities \
-H "Authorization: Bearer sp_live_YOUR_API_KEY"{
"total": 29,
"vulnerabilities": [
{
"id": "vuln-uuid",
"title": "Missing Content-Security-Policy",
"severity": "high",
"category": "Security Headers",
"description": "No CSP header found...",
"remediationGuide": "1. Add a Content-Security-Policy header...",
"endpointUrl": "https://your-domain.com/",
"httpMethod": "HEAD",
"parameter": "content-security-policy",
"cvssScore": 5.4,
"cvssVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N",
"cweId": "CWE-693",
"owaspCategory": "A05:2021",
"fingerprint": "66f6ca2a69942a73bbe8649d296f018215362778",
"reproSteps": ["Send a HEAD request to https://your-domain.com/."],
"curlCommand": "curl -I -s 'https://your-domain.com/'",
"evidence": { "observed": "Header "content-security-policy" is absent from the response." }
}
]
}/api/v1/scans/{id}/summarypérimètre : scans:readRenvoie le verdict pour un seuil de sévérité (fail-on), les failles nouvelles ou corrigées depuis le scan précédent du même hôte, et un commentaire Markdown prêt à publier. Les failles marquées risque accepté ou faux positif ne font pas échouer le verdict.
curl "https://secuprobe.io/api/v1/scans/SCAN_ID/summary?fail-on=high" \
-H "Authorization: Bearer sp_live_YOUR_API_KEY"{
"scanId": "550e8400-...",
"status": "completed",
"secuScore": 78,
"counts": { "critical": 0, "high": 1, "medium": 5, "low": 8, "info": 12 },
"gate": { "failOn": "high", "failed": true, "blocking": 1, "ignored": 0 },
"comparedTo": "3f2b1c9e-...",
"newFindings": [
{ "id": "vuln-uuid", "title": "Reflected XSS", "severity": "high", "url": "https://your-domain.com/search" }
],
"fixedFindings": [],
"markdown": "<!-- secuprobe:scan-comment -->\n### SecuProbe security scan: failed ...",
"marker": "<!-- secuprobe:scan-comment -->",
"reportUrl": "https://secuprobe.io/scan/550e8400-..."
}/api/v1/scans/{id}/sarifpérimètre : scans:readExporte un scan terminé au format SARIF 2.1.0, pour le code scanning de GitHub et tout outil compatible. Le fichier ne contient aucune preuve de requête ou de réponse. Plan Starter et au-dessus.
curl https://secuprobe.io/api/v1/scans/SCAN_ID/sarif \
-H "Authorization: Bearer sp_live_YOUR_API_KEY" \
-o secuprobe.sarif/api/v1/domainspérimètre : domains:readListe tous les domaines validés de votre compte.
curl https://secuprobe.io/api/v1/domains \
-H "Authorization: Bearer sp_live_YOUR_API_KEY"{
"domains": [
{
"id": "domain-uuid",
"hostname": "your-domain.com",
"isValidated": true,
"createdAt": "2026-01-15T10:00:00Z"
}
]
}Codes d'erreur
| Code HTTP | Signification | Action |
|---|---|---|
| 400 | Requête invalide | Vérifiez le corps et les paramètres de la requête |
| 401 | Non authentifié | Vérifiez que la clé d'API est valide et active |
| 403 | Interdit | L'action exige une offre supérieure |
| 404 | Introuvable | La ressource n'existe pas ou ne vous appartient pas |
| 429 | Limite atteinte | Ralentissez et lisez l'en-tête X-RateLimit-Reset |
| 500 | Erreur serveur | Réessayez avec un délai croissant |
Les réponses d'erreur suivent le format : { "error": "Human readable message" }
GitHub Actions
Utilisez l'action GitHub officielle de SecuProbe pour scanner à chaque push ou pull request. Elle fait échouer le job au-delà du seuil fail-on, envoie le rapport SARIF vers l'onglet Security et tient à jour un commentaire unique sur la pull request.
# .github/workflows/security.yml
name: Security Scan
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
pull-requests: write # pull request comment
security-events: write # SARIF upload to the Security tab
jobs:
security:
runs-on: ubuntu-latest
steps:
- name: SecuProbe Security Scan
id: scan
uses: Auxilh/secuprobe-scan-action@v1.1.0
with:
api_key: ${{ secrets.SECUPROBE_API_KEY }}
url: https://staging.your-app.com
fail-on: high # critical | high | medium | low | none
- name: Print score
if: always()
run: |
echo "SecuScore: ${{ steps.scan.outputs.secu_score }}/100"
echo "Report: ${{ steps.scan.outputs.report_url }}"Entrées : api_key (obligatoire), url (obligatoire), fail-on (défaut : critical), timeout (défaut : 600), comment (défaut : true), upload_sarif (défaut : true)
Sorties : scan_id, secu_score, report_url, sarif_file, new_findings, fixed_findings
GitLab CI
Incluez le modèle publié dans votre .gitlab-ci.yml. Rangez la clé d'API dans une variable CI/CD masquée nommée SECUPROBE_API_KEY. Pour obtenir le commentaire de merge request, ajoutez un jeton d'accès de projet avec la portée api dans SECUPROBE_GITLAB_TOKEN.
# .gitlab-ci.yml
include:
- remote: 'https://secuprobe.io/ci/secuprobe.gitlab-ci.yml'
secuprobe:
extends: .secuprobe-scan
variables:
SECUPROBE_URL: 'https://staging.your-app.com'
SECUPROBE_FAIL_ON: 'high' # critical | high | medium | low | noneLe job échoue quand une faille atteint SECUPROBE_FAIL_ON, conserve le rapport SARIF comme artefact et met à jour un commentaire unique sur la merge request, avec les nouvelles failles, les failles corrigées et le lien vers le rapport.
Bitbucket Pipelines
Ajoutez le pipe SecuProbe à bitbucket-pipelines.yml. Rangez SECUPROBE_API_KEY dans une variable de dépôt sécurisée. Pour obtenir le commentaire de pull request, ajoutez un jeton d'accès au dépôt autorisé à écrire sur les pull requests dans SECUPROBE_BITBUCKET_TOKEN. Source : bitbucket.org/secuprobe/scan-pipe.
# bitbucket-pipelines.yml
pipelines:
pull-requests:
'**':
- step:
name: SecuProbe security scan
script:
- pipe: docker://secuprobe/scan-pipe:1.0.0
variables:
SECUPROBE_API_KEY: $SECUPROBE_API_KEY
SECUPROBE_URL: 'https://staging.your-app.com'
SECUPROBE_FAIL_ON: 'high' # critical | high | medium | low | none
SECUPROBE_BITBUCKET_TOKEN: $SECUPROBE_BITBUCKET_TOKEN
artifacts:
- secuprobe.sarifSans le pipe, le même scan s'exécute avec le script publié, dans n'importe quelle étape Alpine :
# bitbucket-pipelines.yml
definitions:
steps:
- step: &secuprobe-scan
name: SecuProbe security scan
image: alpine:3.20
script:
- apk add --no-cache curl jq >/dev/null
- export SECUPROBE_URL="https://staging.your-app.com"
- export SECUPROBE_FAIL_ON="high"
- curl -fsSL https://secuprobe.io/ci/secuprobe-scan.sh -o /tmp/secuprobe-scan.sh
- sh /tmp/secuprobe-scan.sh
artifacts:
- secuprobe.sarif
pipelines:
pull-requests:
'**':
- step: *secuprobe-scan
branches:
main:
- step: *secuprobe-scanGitLab et Bitbucket exécutent le même script, publié à l'adresse https://secuprobe.io/ci/secuprobe-scan.sh. Il demande curl et jq, et se termine avec le code 0 (réussite), 1 (seuil atteint), 2 (erreur de configuration ou d'API) ou 3 (délai dépassé).
Webhooks de déploiement
Un webhook de déploiement lance un scan à la fin de votre déploiement. Créez-en un dans Tableau de bord → Paramètres → Intégrations : il est lié à un domaine validé et possède son propre secret. Signez chaque appel en HMAC-SHA256 sur l'horodatage, un point et le corps brut, puis envoyez le résultat dans X-SecuProbe-Signature.
TS=$(date +%s)
BODY='{"commit":"'"$COMMIT_SHA"'","environment":"production"}'
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECUPROBE_HOOK_SECRET" | sed 's/^.* //')
curl -fsS -X POST https://secuprobe.io/api/hooks/deploy/HOOK_ID \
-H "X-SecuProbe-Timestamp: $TS" \
-H "X-SecuProbe-Signature: sha256=$SIG" \
-d "$BODY"{
"scanId": "550e8400-e29b-41d4-a716-446655440000",
"status": "queued",
"reportUrl": "https://secuprobe.io/scan/550e8400-e29b-41d4-a716-446655440000"
}Un appel est refusé avec 401 quand la signature ne correspond pas, quand l'horodatage s'écarte de plus de cinq minutes de l'horloge du serveur, ou quand le webhook est révoqué. Rejouer le même appel signé ne lance pas un second scan. Le corps est facultatif et ne peut pas désigner une autre cible.
Besoin d'aide ? Consultez notre page d'assistance ou parcourez le catalogue des intégrations.