Developer Documentation
Stryda API
Run adversarial red-team datasets against any LLM endpoint and get a quantified vulnerability-resistance score — straight from your terminal, scripts, or CI pipeline.
Introduction
The Stryda API lets you test any HTTP-accessible language model against curated adversarial prompt datasets. Each request sends a batch of attack prompts to your model, evaluates whether the model resisted each attack, and returns a single resistance score (0–100) plus a per-vector breakdown mapped to OWASP LLM Top 10, MITRE ATLAS, and NIST AI RMF.
The API runs entirely on the edge. There are three dataset tiers — small, medium, and large — each returning a complete JSON result with the score and per-vector breakdown.
Base URL
https://stryda.online
Authentication
Programmatic requests authenticate with an API key passed in the X-API-Key header. Keys are created from your dashboard and shown once at creation — store them in a secrets manager.
X-API-Key: sk_stryda_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx- Keys are prefixed with sk_stryda_.
- Only the SHA-256 hash is stored server-side; the raw key is never persisted.
- Each key carries the datasets:run and datasets:read scopes.
- Up to 5 keys per account. Revoking a key takes effect immediately.
Create and manage keys at /dashboard/api-keys.
Dataset tiers
Each tier defines how many adversarial prompts are sent and how many credits it costs.
| Tier | Prompts | Credits | Price | Best for |
|---|---|---|---|---|
| small | 50 | 2 | $14.40 | Quick smoke test / baseline |
| medium | 150 | 5 | $36.00 | Full coverage across all 10 vectors |
| large | 500 | 10 | $72.00 | Deep audit / compliance testing |
All three tiers are available from both the browser runner and the API, and return a complete JSON result. Credits are deducted atomically before the run starts and automatically refunded if the run fails to start or crashes mid-execution.
Run a scan
POST /api/datasets/api-run
Send a tier and your model's endpoint. The API delivers the prompts to your model, evaluates the responses, and returns the scored result.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| tier | string | Yes | small · medium · large |
| endpoint_url | string | Yes | HTTPS endpoint of the model under test |
| model_id | string | No | Model identifier used for benchmark grouping |
| auth_config | object | No | How to authenticate against your endpoint (see below) |
| evaluation_mode | string | No | heuristic (default) · llm_judge · hybrid |
| fail_threshold | int | No | 0–100. If the score is below this, ci_failed is true |
| publish_to_benchmark | bool | No | Defaults true. Set false to keep the run private |
| pipeline_mode | bool | No | Enable RAG / indirect-injection testing |
Example request
curl -X POST https://stryda.online/api/datasets/api-run \
-H "X-API-Key: sk_stryda_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"tier": "large",
"endpoint_url": "https://api.openai.com/v1/chat/completions",
"model_id": "gpt-4o",
"evaluation_mode": "hybrid",
"auth_config": {
"auth_type": "openai_compatible",
"api_key": "sk-your-provider-key"
}
}'Response
{
"run_id": "0f4c2b9a-1e7d-4a3f-8b21-9c5e7d2a1f00",
"model_id": "gpt-4o",
"tier": "large",
"total_prompts": 500,
"passed": 431,
"failed": 69,
"resistance_score": 86,
"interpretation": { "label": "Low Risk", "severity": "low" },
"vector_scores": {
"markdown_image_exfiltration": 92,
"lexical_concatenation": 78,
"ast_fragmentation": 64
},
"credits_spent": 10,
"ci_failed": false,
"fail_threshold": 0,
"execution_metrics": {
"total_duration_ms": 48213,
"avg_prompt_duration_ms": 96,
"p95_prompt_duration_ms": 210,
"rate_limited_count": 3,
"retry_count": 3,
"failed_count": 0
},
"evaluation_mode": "hybrid",
"pipeline_mode": false
}The resistance_score is the percentage of prompts your model resisted. Prompts that could not be evaluated (network or evaluator errors) are excluded from scoring rather than counted as passes.
Target authentication
Use auth_config to tell Stryda how to authenticate against your model endpoint. The supported auth_type values are:
- openai_compatible — sends Authorization: Bearer <api_key> (default).
- bearer — same Bearer scheme, explicit.
- basic_auth — HTTP Basic using basic_username / basic_password.
- custom_header — sends custom_header_name: custom_header_value.
- none — no auth header.
"auth_config": {
"auth_type": "custom_header",
"custom_header_name": "x-api-key",
"custom_header_value": "abc123"
}Custom header names are validated and reserved headers (Authorization, Host, Cookie, …) cannot be overridden. Header values may not contain control characters.
Evaluation modes
Stryda decides whether a model resisted each attack using one of three modes:
- heuristic — fast, deterministic pattern detection. No extra model calls. Default.
- llm_judge — a judge model scores each response. Most accurate, uses the same endpoint/credentials as the target.
- hybrid — heuristics first, then the judge confirms ambiguous cases. Balanced accuracy and speed.
In llm_judge and hybrid modes, a prompt whose verdict can't be produced is marked as an error and excluded from the score — never silently passed.
RAG pipeline testing
Set pipeline_mode: true to test indirect prompt injection through a retrieval pipeline. For each prompt, Stryda first calls your retrieval_endpoint, injects the adversarial content into the retrieved context, then sends it to your main endpoint.
{
"tier": "large",
"endpoint_url": "https://api.example.com/chat",
"pipeline_mode": true,
"retrieval_endpoint": "https://your-rag.example.com/retrieve",
"retrieval_auth": { "type": "bearer", "token": "rag-token" }
}CI/CD gating
Set fail_threshold to fail a build when the resistance score drops below your bar. The response field ci_failed reflects the gate.
# GitHub Actions step
- name: Stryda AI security scan
run: |
RESULT=$(curl -s -X POST https://stryda.online/api/datasets/api-run \
-H "X-API-Key: ${{ secrets.STRYDA_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{"tier":"medium","endpoint_url":"'"$MODEL_URL"'","model_id":"ci-model","fail_threshold":70}')
echo "$RESULT"
echo "$RESULT" | grep -q '"ci_failed":false' || { echo "Resistance below threshold"; exit 1; }Errors & rate limits
| Status | Meaning |
|---|---|
| 401 | Invalid API key or missing the datasets:run scope |
| 402 | Insufficient credits (response includes credits_required) |
| 422 | Invalid body: bad tier, non-HTTPS URL, blocked host, or unexpected field |
| 429 | Rate limited — includes a Retry-After header |
| 500 | Run failed (credits are refunded) |
- Rate limit: 10 runs per 5 minutes per account.
- SSRF protection: private, loopback, and link-local hosts are rejected.
- Strict bodies: unknown fields are rejected — send only documented keys.
Managing API keys
GET /api/api-keys— list your keys (metadata only)
POST /api/api-keys— create a key, returned once
DELETE /api/api-keys?id=<keyId>— revoke a key
These management endpoints use your logged-in dashboard session, not the API key itself. Manage everything visually at /dashboard/api-keys.
Need a hands-on audit instead?
The API is self-serve red-teaming. For an expert-led engagement with a written report and remediation guidance, open a case with our team.