REST API

The Obexum portal exposes a small, stable HTTP API under /api/v1 for reading your engagements, findings, and signed reports, plus on-demand web and container scan modes. Every /api/v1 endpoint authenticates with a personal API token sent as a bearer credential.

Base URL. All paths below are relative to your portal origin — https://obexum.com for the hosted service, or your own host for a self-hosted deployment. Examples use https://obexum.com.

Authentication

Each /api/v1 request is authenticated with an API token in the Authorization header using the Bearer scheme:

Authorization: Bearer obxk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Tokens are prefixed with obxk_ followed by a random, URL-safe string. The portal stores only a SHA-256 hash of the token, so the plaintext value is shown once, at creation time, and cannot be recovered afterwards — if you lose it, revoke the token and issue a new one.

A request with a missing, malformed, expired, or revoked token receives 401 Unauthorized with a JSON body:

{"error": "unauthorized", "docs": "https://obexum.com/docs/api"}

Browser sessions in the dashboard use cookie authentication; the same /api/v1 endpoints also accept a valid session cookie as a fallback, but bearer tokens are the supported path for programmatic and CI use.

Managing API tokens

API tokens are created and revoked from the authenticated dashboard (cookie session, not a bearer token). The token-management endpoints live under /app/settings/api-tokens and back the API-tokens screen in your account settings.

Create a token

POST/app/settings/api-tokens

Accepts a form-encoded body. Returns the new token's plaintext value exactly once.

FieldRequiredNotes
nameyesHuman label for the token.
scopenoZero or more scope values (repeat the field to send several).
expires_daysnoPositive integer; expiry is set this many days out. Omit for no expiry.

Response body:

{
  "token": {
    "id": "…",
    "name": "ci-readonly",
    "prefix": "obxk_ab12cd34",
    "scopes": [],
    "created_at": "2026-06-17T18:14:39Z"
  },
  "plaintext": "obxk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "warning": "Store this token immediately — it is shown only once."
}

List tokens

GET/app/settings/api-tokens

Returns { "tokens": [ … ] }. Each entry includes id, name, prefix (the leading characters of the plaintext, for display), scopes, created_at, expires_at, last_used_at, and use_count. Plaintext is never returned here.

Revoke a token

POST/app/settings/api-tokens/{id}/revoke

Revokes the token identified by {id}. Returns 204 No Content on success.

Endpoints

The following endpoints are served under /api/v1 and require a bearer token.

MethodPathPurpose
GET/api/v1/engagementsList your engagements
GET/api/v1/engagements/{id}/findingsList findings for an engagement
GET/api/v1/engagements/{id}/findings/summarySeverity counts + compliance score
GET/api/v1/engagements/{id}/report.htmlSigned report (HTML)
GET/api/v1/engagements/{id}/report.pdfSigned report (PDF)
GET/api/v1/engagements/{id}/report.jsonSigned report (JSON)
GET/api/v1/engagements/{id}/report.stixSigned report (STIX 2.1)
GET/api/v1/engagements/{id}/report.stix.jsonSigned report (STIX 2.1 JSON)
POST/api/v1/scan/webRun a DAST web scan
POST/api/v1/scan/containerScan a container image
POST/api/v1/scan/dockerfileStatic-analyze a Dockerfile
POST/api/v1/scan/sbomGenerate a CycloneDX SBOM for an image

List engagements

GET/api/v1/engagements

Returns a JSON array of the engagements owned by the token's user (archived engagements excluded, newest first).

curl https://obexum.com/api/v1/engagements \
    -H "Authorization: Bearer $OBEXUM_TOKEN"

Each element has this shape:

[
  {
    "id": "a3f1c2e4-…",
    "name": "ACME prod RHEL9",
    "description": "",
    "target_os": "rhel-9",
    "scan_profile": "default",
    "status": "active",
    "created_at": "2026-06-15T12:00:00Z",
    "last_scan_at": "2026-06-16T09:31:00Z"
  }
]

List findings

GET/api/v1/engagements/{id}/findings

Returns a JSON array of findings for the engagement, ordered by severity then score. Supports these query parameters:

ParamNotes
severityFilter by severity (e.g. CRITICAL, HIGH, MEDIUM, LOW).
statusOne of open, fixed, suppressed, verifying.
qCase-insensitive substring match on rule_id or title.
limitPage size, 1–500 (default 100).
offsetRow offset for pagination (default 0).
curl "https://obexum.com/api/v1/engagements/a3f1c2e4-.../findings?severity=CRITICAL&status=open&limit=50" \
    -H "Authorization: Bearer $OBEXUM_TOKEN"

Each finding has this shape (fields marked optional are omitted when empty):

[
  {
    "id": "…",
    "rule_id": "AUD-WIN-ADCS-001",
    "title": "AD CS template allows requester-supplied SAN",
    "severity": "CRITICAL",
    "status": "open",
    "category": "identity",
    "score_final": 9.8,
    "kev": false,
    "location_path": "…",
    "location_service": "…",
    "location_port": 0,
    "first_seen_at": "2026-06-15T12:05:00Z",
    "last_seen_at": "2026-06-16T09:31:00Z",
    "tags": { },
    "source": "audit",
    "tier": "verified"
  }
]

The source field names the producing engine (audit is Obexum's validated check engine; advisory engines such as lynis and cvematch also appear), and tier is the derived confidence tier so verified findings are distinguishable from advisory ones.

Findings summary

GET/api/v1/engagements/{id}/findings/summary

Returns aggregate counts and a compliance score for the engagement.

curl https://obexum.com/api/v1/engagements/a3f1c2e4-.../findings/summary \
    -H "Authorization: Bearer $OBEXUM_TOKEN"
{
  "engagement_id": "a3f1c2e4-…",
  "counts": { /* counts per status bucket */ },
  "compliance": 87,
  "per_severity": { /* counts per severity */ }
}

Signed reports

GET/api/v1/engagements/{id}/report.{format}

Generates a report for the engagement. The format is selected by the path suffix: .html, .pdf, .json, .stix, or .stix.json. Every report is signed; the integrity values are returned in response headers:

# Download the signed PDF and capture the integrity headers
curl -D headers.txt \
    https://obexum.com/api/v1/engagements/a3f1c2e4-.../report.pdf \
    -H "Authorization: Bearer $OBEXUM_TOKEN" \
    -o acme-report.pdf

Web scan (DAST)

POST/api/v1/scan/web

Runs a dynamic scan against a live web target. The body is JSON; target must be a full http(s):// URL. The response is the scan result as JSON.

FieldRequiredNotes
targetyesFull http:// or https:// URL.
max_depthnoCrawl depth limit.
max_urlsnoMaximum URLs to crawl.
scan_timeout_secondsnoPer-scan time budget, in seconds.
user_agentnoOverride the request User-Agent.
curl -X POST https://obexum.com/api/v1/scan/web \
    -H "Authorization: Bearer $OBEXUM_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"target":"https://staging.example.com","max_depth":3,"max_urls":200}'

Container image scan

POST/api/v1/scan/container

Scans a container image for known vulnerabilities. Returns the scan result as JSON.

FieldRequiredNotes
imageyesImage reference (e.g. nginx:1.27).
ignore_unfixednoWhen true, omit vulnerabilities with no available fix.
curl -X POST https://obexum.com/api/v1/scan/container \
    -H "Authorization: Bearer $OBEXUM_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"image":"nginx:1.27","ignore_unfixed":true}'

Dockerfile analysis

POST/api/v1/scan/dockerfile

Statically analyzes a Dockerfile. The request body is the raw Dockerfile text (not JSON). Returns { "findings": [ … ], "count": N }.

curl -X POST https://obexum.com/api/v1/scan/dockerfile \
    -H "Authorization: Bearer $OBEXUM_TOKEN" \
    --data-binary @Dockerfile

SBOM export

POST/api/v1/scan/sbom

Generates a CycloneDX 1.5 JSON SBOM for a container image. The body is JSON with a required image field; the response is the SBOM with content type application/vnd.cyclonedx+json.

curl -X POST https://obexum.com/api/v1/scan/sbom \
    -H "Authorization: Bearer $OBEXUM_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"image":"nginx:1.27"}' \
    -o sbom.cdx.json
Scanner uploads use a different credential. The scanner binary uploads its results over a per-engagement token issued when you run the install one-liner — not an API token. You do not need this API to send scan data to the portal; it is for reading results and driving the on-demand web/container scan modes.

Errors

Next steps