API FundamentalsRequests and Responses

Requests and Responses

Learn how Scrut API responses are structured, and how to filter results, add extra fields, paginate, and work with timestamps.

Every /v1 endpoint follows the same conventions for requests and responses. Learn them once, and they apply across policies, controls, evidence, frameworks, tests, and vulnerabilities.

Request Basics

  • Send every request to your region's base URL. See Base URLs.
  • Include your access token in the Authorization header as Bearer followed by the token. See Authentication and Access Tokens.
  • Send JSON request bodies with Content-Type: application/json. Evidence uploads use multipart/form-data instead.
  • Include an Idempotency-Key header on every write request. See Idempotency.

Response Format

Successful /v1 responses use a { data, meta } envelope:

{
  "data": {
    "evidenceId": "37935520-e7d4-40e4-b054-ce546528ac42",
    "modifiedOn": 1715904123000
  },
  "meta": {
    "requestId": "550e8400-e29b-41d4-a716-446655440000"
  }
}
  • data is an object for a single resource and an array for lists.
  • meta.requestId is a unique ID for each request. The same value is returned in the X-Request-Id response header.
  • The vulnerabilities list also returns pagination fields in meta.
  • JSON field names use camelCase.
  • The HTTP status code tells you whether a request succeeded. Response bodies don't include a success flag.
  • Download URLs for files hosted by Scrut are never returned. Document and attachment metadata includes a url only for external links you added yourself.
  • The token endpoint, /oauth/token, returns the standard OAuth token object and doesn't use this envelope.

Failed requests return an error object instead of data. See Errors.

Filtering

List endpoints accept filters as query parameters. Pass multiple values as a comma-separated list.

EndpointFilters
Policies, Evidencestatus, frameworkIds, controlIds, entityIds, isRelevant, assigneeEmails, approverEmails, departments, nextReviewAtFrom, nextReviewAtTo
Controlsstatus, frameworkIds, entityIds, assigneeEmails, domains, functionGroupings, controlScope
FrameworksentityIds
Testsstatus, frameworkIds, assigneeEmails, applications
Vulnerabilitiesstatus, severity, source, fixAvailable

For example, to list published policies and policies that need review:

curl "https://api.scrut.io/v1/policies?status=published,needs_review" \
  -H "Authorization: Bearer $SCRUT_ACCESS_TOKEN"

Filter Rules

  • In assigneeEmails and approverEmails, encode + in plus-addressed emails as %2B.
  • nextReviewAtFrom and nextReviewAtTo are inclusive bounds in Unix epoch milliseconds.
  • Use No Department in departments to match items without a department.
  • Test status values are passing, fix_required, ignored, and affected. A test shows as affected when it passes, but a connected observability integration for automated tests is failing.

Filter Resources on a Single Record

On get test and get vulnerability, use resourceStatus to filter the resources returned:

  • Get test returns fix_required resources by default.
  • On get vulnerability, request affectedResources in fields. Scrut returns open and risk resources by default.

Extra Fields

Use the fields parameter to add data that isn't returned by default. Pass multiple values as a comma-separated list.

  • Extra list columns add fields to each record in a list response.
  • Get expansions add related data to a single-record response.
ResourceExtra list columnsGet expansions
PoliciespolicyBehavior, mappedFrameworkIds, mappedControlIds, notRelevantReason, versionNumber, effortEstimate, recurrence, source, publishedBy, publishedOn, addedBy, addedOn, lastModifiedBy, modifiedOnaiDetectedGaps, documents, versionHistory, tickets
ControlsmappedFrameworkIds, outOfScopeReason, markedOutOfScopeBy, addedBy, addedOn, lastModifiedBy, modifiedOncomplianceOverview, mappedArtifacts, mappedRisks
EvidencemappedFrameworkIds, mappedControlIds, notRelevantReason, recurrence, effortEstimate, source, evidenceCollectionMethod, ticketsCount, addedBy, addedOn, lastModifiedBy, modifiedOnmappedTests, gaps, attachments, tickets
FrameworksaddedBy, addedOn, lastModifiedBy, modifiedOn, tscSelectionsNot applicable
TestsmappedFrameworkIds, effortEstimate, ignoreReason, addedOn, modifiedOn, ticketsCounttickets, mappedRisks, testHistory
VulnerabilitiescvssScore, resourcesCount, firstSeenaffectedResources, tickets, mappedRisks

For example, to include mapped framework IDs and the publish date in a policy list:

curl "https://api.scrut.io/v1/policies?fields=mappedFrameworkIds,publishedOn" \
  -H "Authorization: Bearer $SCRUT_ACCESS_TOKEN"

Pagination

The vulnerabilities list is the only paginated endpoint. All other list endpoints return every matching record in a single array.

  • Set count to 50 or 100 to choose the page size. The default is 50.
  • To fetch the next page, pass meta.nextCursor from the previous response as the nextCursor query parameter. Omit nextCursor on the first page.
  • meta.nextCursor is null on the last page.
  • meta.totalCount is the number of findings that match your filters across all pages.
curl "https://api.scrut.io/v1/vulnerabilities?severity=critical,high&count=100&nextCursor=$NEXT_CURSOR" \
  -H "Authorization: Bearer $SCRUT_ACCESS_TOKEN"

Timestamps

Dates in request bodies, response bodies, and query filters are Unix epoch milliseconds unless noted otherwise. For example, 1735689600000 is January 1, 2025, 00:00:00 UTC.

The one exception is the X-RateLimit-Reset header, which is a Unix timestamp in seconds. See Rate Limits.

IDs in the Path

Use IDs exactly as the API returns them.

Heads Up! The vulnerabilityId returned by list, get, and create is already URL-encoded, for example api%23VUL-5672. Paste it into the path as is. Encoding it again causes a 404 not_found.

Contact support@scrut.io for further assistance.