> ## Documentation Index
> Fetch the complete documentation index at: https://docs.noresponse.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Team, audit log and usage

> Manage non-owner members and invitations, read and stream the audit log, set audit retention, and read usage and console lookups left today, with API keys that carry the team, audit and usage scopes.

Your workspace has members, an audit log and usage counts. API keys with dedicated scopes read and manage them, so your own tools can automate team and compliance work.

| Area | Routes | Scopes |
| - | - | - |
| Members | `GET /v1/workspaces/{workspace_id}/members`, and `PATCH` and `DELETE` on `.../members/{member_id}` | `members` or `members_manage` to read. `members_manage` to change. Live key only. |
| Invitations | `POST` and `GET` on `/v1/workspaces/{workspace_id}/invites`, `DELETE .../invites/{invite_id}` and `POST .../invites/{invite_id}/resend` | `members_manage`. Live key only. |
| Audit events | `GET /v1/workspaces/{workspace_id}/audit` | `audit` or `audit_manage` |
| Audit retention | `GET` and `PATCH` on `/v1/workspaces/{workspace_id}/retention/{environment}` | `audit` or `audit_manage` to read. `audit_manage` on a test key to change test retention. |
| Audit streams | `GET` and `POST` on `/v1/workspaces/{workspace_id}/streams/{environment}`, `DELETE .../{endpoint_id}` and `POST .../{endpoint_id}/replay` | `audit` or `audit_manage` to list. `audit_manage` to change, stop or replay. |
| Usage | `GET /v1/workspaces/{workspace_id}/usage` | `usage` |

`management` alone does not grant any of these routes. Only an owner with access to both environments can issue the `members` and `members_manage` scopes. `members_manage` requires a service key. [Scopes](https://docs.noresponse.org/authentication.md#scopes) lists every scope.

A key without the scope answers 403 [`workspace_forbidden`](https://docs.noresponse.org/problems/workspace-forbidden). A key acts only in its own workspace and environment. A test key on a team route, or a key on the other environment, answers 404 [`not_found`](https://docs.noresponse.org/problems/not-found).

## Roles

Each member holds one role. A role is a built-in set of capabilities.

| Role | What it can do |
| - | - |
| `owner` | Everything, in both environments. Owners cannot be restricted. |
| `admin` | Manage keys, settings, webhooks, integrations, reviews and events, run assessments and record outcomes in its granted environments. Admins read members and the audit log. Admins cannot change members or delete data. |
| `developer` | Manage test keys. Run assessments, record outcomes and manage webhooks, integrations, reviews and events in the test environment. Read live data. Developers cannot change settings or delete data. |
| `viewer` | Read workspace data, events included, in its granted environments. |
| `investigator` | Read investigation data, run assessments, record outcomes, operate reviews, and read groups and record decisions on people. Investigators cannot change policy or issue keys. |
| `auditor` | Read members, the audit log, settings, usage and events. Auditors cannot read assessments or accounts. |
| `billing` | Read usage. Read the billing period and change its budgets in the NoResponse console. |

Two more fields narrow a role:

* `environments` limits the member to `["live"]`, `["test"]` or both. An invitation grants both when you omit it. Owners always keep both.
* `denied_actions` takes away up to three capabilities from the role: `evidence.read` (detailed evidence and submitted identifiers), `exports.read` (exports) and `policy.publish` (active policy publication). An empty array clears the exclusions.

A change to a member's role, environments or `denied_actions` applies to the next request. It also revokes the personal keys of that member.

## Members

```bash title="List members" theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
curl https://api.noresponse.org/v1/workspaces/tnt_01JA2Z8K6Q4V7W9XBCDEFGHJKM/members \
  -H "Authorization: Bearer $NORESPONSE_TEAM_API_KEY"
```

The answer lists active members, oldest first. Each member has a stable id that starts with `mem_`, its `external_user_id` at the identity provider of the console, `role`, `environments` and `denied_actions`.

`PATCH /v1/workspaces/{workspace_id}/members/{member_id}` changes a non-owner member. The body must have `role`. An omitted `environments` or `denied_actions` keeps its current value.

```bash title="Make a member an investigator with test access only" theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
curl -X PATCH https://api.noresponse.org/v1/workspaces/tnt_01JA2Z8K6Q4V7W9XBCDEFGHJKM/members/mem_01JA2ZB4C5D6E7F8G9H0JKMNPQ \
  -H "Authorization: Bearer $NORESPONSE_TEAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "role": "investigator", "environments": ["test"], "denied_actions": ["exports.read"] }'
```

`DELETE /v1/workspaces/{workspace_id}/members/{member_id}` revokes the workspace access of a non-owner member and answers 204. The member loses access at once. A later invitation restores the member with the same `mem_` id.

API keys cannot make, change or invite owners, or revoke their access. An owner as the target answers 404 [`not_found`](https://docs.noresponse.org/problems/not-found).

## Invitations

An invitation lets a person join the workspace with a role. Its lifecycle has four calls.

**1. Create the invitation**

`POST /v1/workspaces/{workspace_id}/invites` answers 201 with the invitation and its secret `token`. NoResponse shows the token once.

```bash title="Invite a developer" theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
curl -X POST https://api.noresponse.org/v1/workspaces/tnt_01JA2Z8K6Q4V7W9XBCDEFGHJKM/invites \
  -H "Authorization: Bearer $NORESPONSE_TEAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "role": "developer", "email": "dev@example.com" }'
```

`email` is for your records. NoResponse does not match it against the person who accepts. Set `external_user_id` instead to let only that user accept.

**2. Deliver the token**

This call sends no email. Give the token to the person through a secure channel. The token works once and expires after seven days.

**3. List pending invitations**

`GET /v1/workspaces/{workspace_id}/invites` lists pending non-owner invitations, oldest first, without tokens.

**4. Revoke or reissue**

`DELETE /v1/workspaces/{workspace_id}/invites/{invite_id}` revokes an invitation and answers 204. Its token stops working.

`POST /v1/workspaces/{workspace_id}/invites/{invite_id}/resend` with an empty body `{}` replaces the token and renews the seven-day expiry. It also renews an expired invitation. The invitation keeps its id and grants. The old token stops working at once. Each call makes a new token. An accepted or revoked invitation answers 404 [`not_found`](https://docs.noresponse.org/problems/not-found).

The invited person accepts the invitation in the NoResponse console. API keys cannot accept invitations. A workspace has at most 100 active members and 50 pending invitations. More answers 409 [`member_limit_reached`](https://docs.noresponse.org/problems/member-limit-reached). An invitation with the `external_user_id` of an active member answers 409 [`already_member`](https://docs.noresponse.org/problems/already-member).

## Audit events

The audit log records each privileged change in your workspace: its actor, action, target, outcome and time. A successful change and its audit event commit together. Events hold no secrets and no submitted identifiers.

```bash title="Get denied key changes from the last day" theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
curl -G https://api.noresponse.org/v1/workspaces/tnt_01JA2Z8K6Q4V7W9XBCDEFGHJKM/audit \
  -H "Authorization: Bearer $NORESPONSE_AUDIT_API_KEY" \
  --data-urlencode "target_type=key" \
  --data-urlencode "outcome=denied" \
  --data-urlencode "since=2026-10-28T00:00:00Z"
```

All filters are optional and apply before paging:

| Parameter | Filter |
| - | - |
| `environment` | `live`, `test` or `workspace`. An API key can request only its own environment. |
| `action` | An exact action, for example `key.created`, `member.role_changed` or `invite.accepted`. |
| `actor` | An exact external user id, API key id or console credential id. |
| `target_type` | An exact target kind, for example `key`, `member`, `invite`, `setting` or `workspace`. |
| `target_id` | The public id of the target. |
| `outcome` | `succeeded` or `denied`. `denied` means the role did not allow the change and nothing changed. |
| `since` | Inclusive RFC 3339 start time. |
| `until` | Exclusive RFC 3339 end time. It must follow `since`. |

Each page holds up to `limit` events, from 1 to 100, with a default of 20. Events arrive newest first. When another page exists, the answer has `next_cursor`. Send it as `cursor` and keep every filter the same.

Each event has `actor.type` `user` or `api_key`. `affected_environment` is `workspace` for member and invitation changes. Only console members with access to both environments read these workspace-wide events. An API key reads only the events of its own environment. `request_id` links the event to the `X-Request-ID` of the request.

## Audit retention

Each environment keeps audit events for `retention_days`, from 1 to 365. The default is 365. The live policy also covers workspace-wide events.

```bash title="Read test audit retention" theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
curl https://api.noresponse.org/v1/workspaces/tnt_01JA2Z8K6Q4V7W9XBCDEFGHJKM/retention/test \
  -H "Authorization: Bearer $NORESPONSE_AUDIT_API_KEY"
```

The answer has `retention_days` and `oldest_available_at`. `oldest_available_at` does not prove that capture was complete before that time.

A test key with `audit_manage` changes test retention with `PATCH` and a body such as `{ "retention_days": 90 }`. Change live retention in the NoResponse console, as a member with both environment grants and audit administration access.

> [!WARNING]
>
> A shorter retention hides expired events at once and invalidates the audit exports of that environment. A shorter live retention also invalidates the workspace-wide audit exports. A longer retention does not restore deleted events.

## Audit streams

An audit stream sends each new audit event to one of your webhook endpoints as a signed `audit.event` webhook. Use it to keep the audit log in your own SIEM or compliance store.

> [!NOTE]
>
> You need a registered and verified webhook endpoint in the same environment. See [Webhooks](https://docs.noresponse.org/guides/webhooks.md).

**1. Configure the stream**

`POST /v1/workspaces/{workspace_id}/streams/{environment}` creates or updates the subscription for one endpoint. A key uses the environment of the key. The `workspace` environment streams workspace-wide events, and only a console member with access to both environments can use it.

```bash title="Stream key and member changes" theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
curl -X POST https://api.noresponse.org/v1/workspaces/tnt_01JA2Z8K6Q4V7W9XBCDEFGHJKM/streams/live \
  -H "Authorization: Bearer $NORESPONSE_AUDIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "endpoint_id": "whe_01JA2Z8K6Q4V7W9XBCDEFGHJKM", "actions": ["key.created", "member.access_changed"] }'
```

`actions` takes up to 32 action names. An empty array sends every action in that environment.

**2. Receive audit.event**

The stream starts at subscription creation. For earlier events, use an [audit export](https://docs.noresponse.org/reference/data-retention.md#export-jobs). Verify the signature before you parse the body. Deliveries can repeat and arrive out of order, so deduplicate on the webhook `id`. See [audit.event](https://docs.noresponse.org/guides/webhooks.md#audit-event).

**3. Check delivery health**

`GET /v1/workspaces/{workspace_id}/streams/{environment}` lists up to 10 subscriptions. Each has `endpoint_state` (`unverified`, `verified` or `disabled`), `last_attempt_at` and `last_delivered_at`.

To send one event again, call `POST /v1/workspaces/{workspace_id}/streams/{environment}/{endpoint_id}/replay` with `{ "event_id": "evt_..." }`. The body and event id stay the same, with a new signature. The current subscription, action filter and retention must still permit the event. Audit deliveries stay replayable for at most 30 days. The ordinary webhook replay route refuses audit events.

`DELETE /v1/workspaces/{workspace_id}/streams/{environment}/{endpoint_id}` stops the stream and cancels its queued deliveries. The endpoint stays registered for other event types.

## Usage

`GET /v1/workspaces/{workspace_id}/usage` answers daily usage counts for the environments that you can access. A key with `usage` reads its own environment. The counts have no prices.

```bash title="Get usage for October" theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
curl -G https://api.noresponse.org/v1/workspaces/tnt_01JA2Z8K6Q4V7W9XBCDEFGHJKM/usage \
  -H "Authorization: Bearer $NORESPONSE_USAGE_API_KEY" \
  --data-urlencode "from=2026-10-01" \
  --data-urlencode "to=2026-10-29"
```

`from` and `to` are UTC days as `YYYY-MM-DD`. NoResponse includes the `to` day. It cannot be later than today. Without `from` and `to`, the range is the 30 days that end today. With only one of them, the range is the 30 days that start or end on that day. A range is at most 366 days.

```json title="200 response" theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
{
  "workspace_id": "tnt_01JA2Z8K6Q4V7W9XBCDEFGHJKM",
  "from": "2026-10-01",
  "to": "2026-10-29",
  "items": [
    { "environment": "live", "day": "2026-10-28", "metric": "assessments", "flow": "account_creation", "depth": "full", "count": 412 },
    { "environment": "live", "day": "2026-10-28", "metric": "webhook_deliveries", "count": 398 },
    { "environment": "test", "day": "2026-10-28", "metric": "screenings", "count": 240 }
  ],
  "console_lookups": { "used": 12, "limit": 50, "resets_at": "2026-10-30T00:00:00.000Z" }
}
```

**items** `object[]`

One item for each environment, day, metric, flow and depth with a count above 0. Live comes first.

* `assessments` counts admitted assessments, with `flow` and `depth`.
* `webhook_deliveries` counts one delivery for each event and endpoint. Retries and replays add nothing.
* `key_usage_events` counts accepted key-usage events.
* `screenings` counts one unit for each person that a screening screens. A screening counts each person one time. A person that a screening could not cover counts nothing.

A count does not change when you later delete the assessment, account or workspace.

**console\_lookups** `object`

The daily cap on the assessments that members make in the live console playground. `used` is the lookups spent since the last reset. `limit` is the lookups allowed per UTC day. `resets_at` is the next midnight UTC, when `used` returns to 0. API keys spend no lookups. At the cap, the next console lookup answers 429 [`lookup_limit_reached`](https://docs.noresponse.org/problems/lookup-limit-reached).

It is present only when the caller can read the live environment and the API enforces the cap. A test key or a member with test access only does not get it. `from` and `to` do not change it.

### Assessment budgets

Your workspace can have an assessment allowance for each billing period and a hard budget. A member with the `billing` role sets the budget in the NoResponse console. When a new assessment would exceed either, `POST /v1/assessments` answers 429 [`assessment_budget_exhausted`](https://docs.noresponse.org/problems/assessment-budget-exhausted). The refused assessment does not spend a usage unit. Compare the `assessments` counts in your usage with your allowance to see how close you are to the limit.

### Screening budgets

The billing period and its budgets apply to assessments. The `screenings` units count in the billing period and its settlements, but they have no price there. The spend of screenings has its own limit for each day: the [`screening_daily_cap`](https://docs.noresponse.org/reference/settings#cap-screening-spend) setting of each environment.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.