curl quickstart
A minimal walkthrough for anyone who wants to start using the API in a few minutes.
Prerequisites
- Access to a RuleForge instance (URL + organization).
- A role that can create API keys (
org_adminor equivalent). curlinstalled.
We define environment variables for the example:
export RF_BASE="http://localhost:8000/api/v1"
export RF_KEY="rfk_YOUR_KEY_HERE"
1. Create an API key
Via UI: Settings → API keys → New key. Pick at least the analysis:run and projects:read scopes. The full value is shown once — copy it and save into $RF_KEY.
Via API (if you already have admin auth):
curl -X POST "$RF_BASE/platform/organizations/$ORG_ID/api-keys" \
-H "X-API-Key: $ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "CI pipeline",
"scopes": ["analysis:run", "projects:read"],
"expires_at": "2027-04-24T00:00:00Z"
}'
The response includes api_key with the secret. Use it as $RF_KEY.
2. Confirm the key works
curl -s "$RF_BASE/health" -H "X-API-Key: $RF_KEY"
# => {"status":"ok"}
A 401 means the key is wrong or expired. A 200 means you're good — proceed.
3. Validate a ruleset
The most common endpoint: POST /analysis/validate. It compiles a set of rules/decoders (including disk baselines if you want) and returns diagnostics.
curl -X POST "$RF_BASE/analysis/validate" \
-H "X-API-Key: $RF_KEY" \
-H "Content-Type: application/json" \
-d '{
"include_disk_defaults": true,
"include_disk_custom": false,
"files": [
{
"filename": "local_rules.xml",
"kind": "rules",
"scope": "adhoc",
"content": "<group name=\"local\"><rule id=\"100010\" level=\"3\"><description>Manual test</description><group>local_test</group></rule></group>"
}
]
}'
Summary response:
{
"ok": true,
"summary": {
"total_rule_files": 1,
"total_decoder_files": 0,
"total_rules": 8621,
"total_decoders": 623,
"compiled_hash": "abc123…",
"loaded_from_disk": true
},
"diagnostics": [],
"baseline_issue_count": 0,
"performance": {
"source_build_ms": 45.2,
"compile_ms": 120.5,
"total_ms": 165.7,
"cache_hit": false
}
}
ok: true→ valid ruleset.diagnostics[]lists errors and warnings from your content (baseline is hidden by default;baseline_issue_countshows how many were filtered out).
If ok: false, read diagnostics[].message and diagnostics[].line to locate the problem.
4. Test an event against the ruleset
POST /analysis/logtest-native runs the full pipeline (predecoder → decoder → rule) over a single event.
curl -X POST "$RF_BASE/analysis/logtest-native" \
-H "X-API-Key: $RF_KEY" \
-H "Content-Type: application/json" \
-d '{
"include_disk_defaults": true,
"include_disk_custom": false,
"files": [],
"input": {
"event": "Jan 10 12:00:01 web01 sshd[1234]: Failed password for root from 10.0.0.5 port 44218 ssh2",
"log_format": "syslog"
}
}'
Response (summarized):
{
"ok": true,
"predecoded": {
"timestamp": "Jan 10 12:00:01",
"hostname": "web01",
"program_name": "sshd",
"raw_message": "Failed password for root from 10.0.0.5 port 44218 ssh2",
"detected_format": "syslog"
},
"decoder": { "name": "sshd", "parent": null, "order": ["srcip", "dstuser"] },
"rule": {
"id": "5716",
"level": 5,
"description": "sshd: authentication failed.",
"groups": ["syslog", "sshd", "authentication_failed"],
"matched": true
},
"extracted_fields": { "dstuser": "root", "srcip": "10.0.0.5" },
"trace": [
{ "phase": "predecode", "name": "predecoder", "matched": true },
{ "phase": "decode", "name": "sshd", "matched": true },
{ "phase": "rule", "name": "5716", "matched": true }
]
}
Read:
rule→ the rule that matched (may benullwhen nothing matches).matched_rules→ full list when multiple rules match.extracted_fields→ values the decoder extracted.trace→ steps executed; useful to debug a decoder that doesn't match.insights→ natural-language tips generated by the backend.
5. Create a project
If you're going to automate the content lifecycle, start by creating a project:
curl -X POST "$RF_BASE/platform/projects" \
-H "X-API-Key: $RF_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Edge rules",
"description": "Custom rules for the edge team",
"ruleset_version": "baseline-4.10"
}'
Save the returned id — you'll use it on every subsequent call.
6. Create a test case
Cases are events + expectations that run in regression:
curl -X POST "$RF_BASE/platform/projects/$PROJECT_ID/cases" \
-H "X-API-Key: $RF_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "SSH brute force",
"event": "Jan 10 12:00:01 web01 sshd[1234]: Failed password for root from 10.0.0.5",
"log_format": "syslog",
"expected_rule_id": "5716",
"expected_level": 5
}'
7. Run every case at once
curl -X POST "$RF_BASE/platform/projects/$PROJECT_ID/cases/run" \
-H "X-API-Key: $RF_KEY"
The response includes passed, failed and the detailed list of each case.
Full sample script
#!/usr/bin/env bash
set -euo pipefail
: "${RF_BASE:?}"
: "${RF_KEY:?}"
# 1. validate
curl -fsS -X POST "$RF_BASE/analysis/validate" \
-H "X-API-Key: $RF_KEY" \
-H "Content-Type: application/json" \
-d @payload.json | jq '{ok, diagnostic_count: (.diagnostics | length)}'
# 2. logtest
curl -fsS -X POST "$RF_BASE/analysis/logtest-native" \
-H "X-API-Key: $RF_KEY" \
-H "Content-Type: application/json" \
-d @logtest.json | jq '{rule: .rule.id, matched: .rule.matched}'
Next steps
- Analysis endpoints — details and full schemas.
- Projects endpoints — CRUD, cases, versions, reviews.
- Webhooks — receive
validation.completed,regression.passed, etc. events. - Authentication — recommended scopes by use case.
Tips
- Send
x-locale: en-USif you want messages in English. - The response's
X-Request-Idheader helps support. include_disk_defaults=trueuses the Wazuh ruleset shipped with the server — you don't need to send baselines along.- In CI pipelines, validate before running logtest: if validate failed → stop there.