Skip to main content
Developers

afend:. v1 API

Read + write access to your workspace ISMS state. Bearer auth with per-token scopes, per-token rate limit (600 reads/min, 60 writes/min), HMAC-signed outbound webhooks, and an OpenAPI 3.1 spec for codegen.

Auth

Pass the token as a Bearer header. Tokens start with afend_; the plain value is shown once at issue time and stored as sha256-only on our side.

curl -H "Authorization: Bearer afend_..." \
  https://afend.com/api/v1/me

Reads

  • GET/api/v1/me

    Token + workspace metadata

    Returns the workspace the token authenticates against and the scopes it carries. Use as a connectivity probe.

    Scope: read:controls

    Response

    {
      "workspace": {
        "id": "uuid",
        "name": "Acme Corp",
        "slug": "acme",
        "industry_profile": "saas"
      },
      "token": {
        "id": "uuid",
        "scopes": [
          "read:controls",
          "read:alerts"
        ]
      },
      "api_version": "v1"
    }
  • GET/api/v1/controls

    Annex A controls + workspace SoA

    All 93 ISO/IEC 27001:2022 Annex A controls joined with the workspace's Statement of Applicability decision and implementation status.

    Scope: read:controls

    Response

    {
      "workspace_id": "uuid",
      "count": 93,
      "items": [
        {
          "id": "A.5.1",
          "title": "Policies for information security",
          "theme": "organizational",
          "requirement": "...",
          "applicability": "applicable",
          "implementation_status": "implemented",
          "has_owner": true,
          "inclusion_justification": null,
          "exclusion_justification": null
        }
      ]
    }
  • GET/api/v1/integrations/checks

    Continuous monitoring check rows

    Live integration_check rows. Filter by status (pass / fail / unknown) and / or control_ref (Annex A id).

    Scope: read:integrations

    Query

    • status (string) pass | fail | unknown
    • control_ref (string) Annex A id, e.g. A.8.32
    • limit (integer) 1..1000, default 200
  • GET/api/v1/alerts

    Continuous monitoring alerts

    Lifecycle of regression alerts. Default: only open alerts, newest first.

    Scope: read:alerts

    Query

    • state (string) open | resolved | all (default open)
    • severity (string) low | medium | high | critical
    • limit (integer) 1..500, default 100
  • GET/api/v1/audit/events

    Governance event log

    Append-only governance events ordered ascending by created_at. Poll incrementally with `since`. The response carries `next_cursor` (last event's created_at) for the next request.

    Scope: read:audit

    Query

    • since (string (ISO 8601)) Only events with created_at strictly greater than this timestamp.
    • limit (integer) 1..1000, default 500

Writes

  • POST/api/v1/alerts/{id}/acknowledge

    Acknowledge an open alert

    Marks the alert as triaged without closing it. Idempotent on re-ack.

    Scope: write:alerts

    Body

    {
      "note": "Investigating - acme team paused the change."
    }

    Response

    {
      "id": "uuid",
      "acknowledged_at": "2026-04-29T12:00:00Z",
      "note": "..."
    }
  • POST/api/v1/alerts/{id}/resolve

    Manually resolve an alert

    Closes the alert and fires a PagerDuty resolve event for any PagerDuty channel in the workspace (same dedup_key as the trigger).

    Scope: write:alerts

    Body

    {
      "note": "Resource decommissioned; alert no longer applies."
    }

    Response

    {
      "id": "uuid",
      "resolved_at": "2026-04-29T12:05:00Z",
      "note": "..."
    }
  • POST/api/v1/audit/events

    Record a partner-attributed governance event

    Inserts a row in the workspace audit trail with actor_email = "api:<token_id>". Caller-supplied event_types without a dot are namespaced under "external." so internal vs API-sourced events stay distinguishable.

    Scope: write:audit

    Body

    {
      "event_type": "deploy.completed",
      "subject_type": "service",
      "subject_id": "checkout-api",
      "summary": "Deployed checkout-api v2.14.0 to production",
      "metadata": {
        "commit": "abc123",
        "deployer": "alice@acme.com"
      }
    }

    Response

    {
      "id": "uuid",
      "created_at": "2026-04-29T12:00:00Z",
      "event_type": "external.deploy.completed"
    }

Outbound webhooks

Subscribe to governance events from the workspace. Each enabled subscription receives one HTTP POST per matching event with an HMAC-SHA-256 signature in X-AFEND-Signature. Configure under Audit trail.

POST https://yourapp.com/afend
X-AFEND-Signature: sha256=<hex>
X-AFEND-Event-Type: dpia.approved
Content-Type: application/json

{
  "api_version": "v1",
  "event_id": "uuid",
  "event_type": "dpia.approved",
  "occurred_at": "2026-04-29T12:00:00Z",
  "workspace_id": "uuid",
  "actor": "alice@acme.com",
  "subject": { "type": "dpia", "id": "uuid" },
  "summary": "DPIA approved by alice",
  "metadata": { "version": 3 }
}

Rate limit

Per-token sliding-window quota: 600 reads / minute and 60 writes / minute. Over-quota requests get HTTP 429. Counters are scoped per token, so two API consumers do not interfere with each other - issue one token per integration so a noisy partner does not starve the rest.