heyGRC API reference

Base URL: https://api.heygrc.com

All requests authenticate with a per-org API key as a Bearer token:

Authorization: Bearer hgrc_...

A key belongs to one heyGRC org (one per GitHub App installation) and carries scopes (config:read, config:write). Send the key in the header only — keys passed in the URL are rejected (400), to avoid leaking them into logs and referrers. The org a request acts on is always derived from the key, so a key can only ever read or write its own org's config.


GET /v1/config

Returns your org's current configuration. Scope: config:read.

200

{
  "profile": { "company": "Acme Inc", "...": "..." },
  "frameworks": ["ISO_27001", "SOC_2", "GDPR"]
}

PUT /v1/config

Full-replace your org's configuration. Idempotent: the body is the complete desired state (anything you omit is cleared). Scope: config:write.

Headers: Content-Type: application/json; optional Idempotency-Key: <string> (logged for safe retries).

Body

FieldTypeNotes
profileobject (required)Free-form company context. Must be a JSON object, ≤ 16 KB, max nesting depth 4, values are strings / numbers / booleans / arrays of those.
frameworksstring[] (required)The framework ids you must comply with. Every id must be in the catalog — unknown ids are rejected, not silently dropped.

200

{ "ok": true, "profile": { "...": "..." }, "frameworks": ["ISO_27001", "SOC_2", "GDPR"] }

A 200 is only returned after the change and its audit record are committed together, so a successful write is always auditable.


Errors

Stable JSON shape on every error:

{ "error": { "code": "unknown_frameworks", "message": "unknown framework ids: FOO", "unknown": ["FOO"] } }
StatuscodeMeaning
400invalid_requestNon-JSON body, wrong body shape, or a key was passed in the URL.
401unauthorizedMissing, malformed, invalid, expired, or revoked key.
403forbiddenThe key lacks the required scope (config:read / config:write).
422invalid_profileprofile isn't an object, is too large, or is too deeply nested.
422unknown_frameworksOne or more framework ids aren't in the catalog (see unknown).
429rate_limitedToo many requests; slow down.

Rate limits

Per-key and per-IP request caps protect the service. Stay under ~1 request/second and you'll never see a 429. Config is a control plane — you set it occasionally, not in a hot loop.


GET /v1/frameworks

The full, machine-readable catalog (no auth — point your agent here to discover valid ids):

{ "frameworks": [ { "id": "ISO_27001", "name": "ISO 27001:2022", "region": "International" }, … ] }

Framework catalog

heyGRC knows ~79 frameworks. Pass the canonical id in frameworks. The most common ids:

ISO_27001, ISO_42001, ISO_27701, ISO_22301, ISO_9001, SOC_2, GDPR, UK_GDPR, HIPAA, CCPA, EU_AI_ACT, NIST_CSF, NIST_800_53, NIST_800_171, NIST_AI_RMF, DORA, TISAX, CMMC, FEDRAMP, CYFUN, AU_ESSENTIAL_EIGHT, and NIS 2 as NIS_2 plus per-country variants (NIS_2_DE, NIS_2_FR, NIS_2_IT, …).

A PUT with an id outside the catalog is rejected with 422 unknown_frameworks and the offending ids echoed back, so your agent can self-correct.