Developers

Resolute Security API

A small REST API for the things you'd want to automate: list monitored domains, fetch their latest scan, trigger a rescan, and feed in DMARC aggregate reports. Bearer-token auth, Pro-plan only.

Authentication

Every request must include an Authorization header with a Bearer API key. Keys are scoped to a single organization and require an active Pro subscription. Mint and revoke keys from Settings → API keys. The raw token is shown exactly once at creation time — copy it then.

Header

Authorization: Bearer smb_YOUR_TOKEN_HERE

Keys are prefixed with smb_ so you can spot them in logs. They never expire; revoke them explicitly when a key is no longer needed. We track lastUsedAt on every successful request so you can spot stale credentials.

Limits & scopes

  • Plan gate: Pro only. Free and Starter keys receive 403 forbidden until the org upgrades.
  • Scope: a key only sees data from the organization that minted it. Cross-tenant ids return 404 not_found.
  • Rate limits: there is no hard per-key rate limit today. Be reasonable — keep your polling above a minute or so, and prefer rescan webhooks over busy loops. We reserve the right to add rate limits without notice if we see abuse.
  • Payload size:DMARC report uploads are capped at 5 MiB. Other endpoints don't accept request bodies.
  • TLS: required. HTTP requests are not accepted.

Endpoints

All endpoints live under https://tools.resolute-security.com. Successful responses wrap the payload in a top-level data envelope; errors use error: { code, message }.

GET

/api/v1/monitored-domains

List monitored domains

Returns every monitored domain in your organization with its current overall score (from the latest successful scan), active/paused state, and the timestamp of the most recent scan.

Request

curl https://tools.resolute-security.com/api/v1/monitored-domains \
  -H "Authorization: Bearer smb_YOUR_TOKEN_HERE"

Response — 200 OK

{
  "data": [
    {
      "id": "01J9...",
      "domain": "example.com",
      "isActive": true,
      "lastScannedAt": "2026-05-19T14:02:11.000Z",
      "latestScanId": "01J9...",
      "createdAt": "2026-03-04T10:14:55.000Z",
      "latestScore": 87,
      "latestScanCompletedAt": "2026-05-19T14:02:11.000Z"
    }
  ]
}
GET

/api/v1/monitored-domains/:id

Get one monitored domain

Returns a single monitored domain with its latest scan (status, score, raw results, duration) and the ten most recent scan-diff rows. Returns 404 when the id is unknown, or when it belongs to a different organization.

Request

curl https://tools.resolute-security.com/api/v1/monitored-domains/01J9... \
  -H "Authorization: Bearer smb_YOUR_TOKEN_HERE"

Response — 200 OK

{
  "data": {
    "domain": {
      "id": "01J9...",
      "domain": "example.com",
      "isActive": true,
      "lastScannedAt": "2026-05-19T14:02:11.000Z",
      "latestScanId": "01J9...",
      "createdAt": "2026-03-04T10:14:55.000Z"
    },
    "latestScan": {
      "id": "01J9...",
      "status": "completed",
      "overallScore": 87,
      "results": { /* per-check details */ },
      "completedAt": "2026-05-19T14:02:11.000Z",
      "durationMs": 4823,
      "shareToken": "..."
    },
    "recentChanges": [
      {
        "id": "01J9...",
        "scanId": "01J9...",
        "previousScanId": "01J9...",
        "overallScoreDelta": -3,
        "hasStatusChange": true,
        "isRegression": true,
        "changes": { /* per-check diff */ },
        "createdAt": "2026-05-19T14:02:11.000Z"
      }
    ]
  }
}
POST

/api/v1/monitored-domains/:id/rescan

Trigger a manual rescan

Enqueues a fresh scan for the given monitored domain. Same dedup-by-timestamp behavior as the in-app Rescan now button. Returns 202 with the queue job id once the work is accepted.

Request

curl -X POST https://tools.resolute-security.com/api/v1/monitored-domains/01J9.../rescan \
  -H "Authorization: Bearer smb_YOUR_TOKEN_HERE"

Response — 202 Accepted

{
  "data": {
    "enqueued": true,
    "jobId": "monitored:01J9...:api:1747750000000",
    "domain": "example.com"
  }
}
POST

/api/v1/dmarc/reports

Upload a DMARC aggregate report

Accepts a single DMARC aggregate XML report in the request body. Pass the XML directly (any content-type is accepted; receivers send the wrong header often enough that we don't enforce). The body must be at most 5 MiB. Repeated uploads of the same report id are deduplicated, so retry-on-failure is safe.

Request

curl -X POST https://tools.resolute-security.com/api/v1/dmarc/reports \
  -H "Authorization: Bearer smb_YOUR_TOKEN_HERE" \
  -H "Content-Type: application/xml" \
  --data-binary @report.xml

Response — 201 Created (new) / 200 OK (duplicate)

// 201 Created — new report ingested
{
  "data": {
    "reportId": "01J9...",
    "recordCount": 14,
    "totalMessages": 4231
  }
}

// 200 OK — duplicate, already on file
{
  "data": {
    "duplicate": true,
    "existingReportId": "01J9..."
  }
}

Errors

Every error response uses the same envelope:

{
  "error": {
    "code": "unauthorized",
    "message": "Provide a valid Bearer token."
  }
}
StatusCodeMeaning
401unauthorizedAuthorization header missing, malformed, or the token doesn't match any active key. Mint a new key in settings if yours was revoked.
403forbiddenThe token is valid but the organization is not on an active Pro subscription. Upgrade on /pricing or check that billing isn't past due.
404not_foundThe resource doesn't exist in your organization. We return 404 (not 403) for cross-tenant ids to avoid leaking that they exist elsewhere.
400bad_bodyRequest body couldn't be read (network truncation, unreadable stream).
400empty_bodyPOST body was empty when a payload was required.
400invalid_xmlDMARC XML couldn't be parsed, was missing required fields, or referenced an unknown report format.
413too_largeRequest body exceeded the 5 MiB cap (DMARC report uploads).

Changelog

  • v1.0.0 2026-05-19

    Initial release.

Questions, missing endpoints, or stuck on integration? Get in touch.