API
The management API under /v1/<namespace-id>. Endpoints for configuration, rules, exceptions, logs, metrics, observations, audit, webhooks, tokens, teams, and Trusted Builders.
The management API is what the dashboard and the CLI use. Everything lives under the namespace ID prefix:
https://eu-sov-1.bytesafecloud.eu/v1/<namespace-id>/...Package traffic (the ecosystem protocol endpoints under /npm/, /pypi/, /maven/, /nuget/, /go/, /conda/) shares the same prefix and authentication; those endpoints are documented per ecosystem. This page covers the management surface.
Authentication
Every endpoint except the OIDC exchange requires a token in the Authorization header, Bearer or basic auth; formats, interaction ID suffix, and the credential envelope are in the tokens reference. Endpoints enforce the permissions noted below; all of them additionally require ns:access.
Responses are JSON. Errors carry a requestId for correlation with logs.
Configuration
| Method and path | Description | Permission |
|---|---|---|
GET /config | List firewalls | fw:read per firewall |
GET /config/<firewall-id> | Full config, credentials redacted | fw:read |
PUT /config/<firewall-id> | Upsert full config; creates when the ID is new. The ID must be a valid firewall ID. Plaintext credentials rejected. On create, accepts an owner team in the body and defaults the permissions map when omitted | fw:update:config (+fw:create for new) |
DELETE /config/<firewall-id> | Delete the firewall. 409 when other firewalls inherit from it | fw:delete |
GET /config/<firewall-id>/history | Last 20 config versions | fw:read |
PUT /config/<firewall-id>/version/{version} | Roll back to a recorded version; creates a new version. 404 for a version not in history | fw:update:config |
PUT /config/<firewall-id>/upstreams/{id}/credentials | Set upstream credentials, plaintext body, per-field merge | fw:update:credentials |
GET /config/<firewall-id>/upstreams/inherited | Only inherited upstreams, including entries overridden by a nearer firewall in the chain. Credentials are redacted | fw:read |
Config upserts and rollbacks reject an unknown ecosystem, invalid upstream settings, unparseable version ranges, unknown upstreamType values, the legacy selector key internal, and selector functions that do not support the firewall's ecosystem. A parentId must also name an existing same-ecosystem firewall without creating a cycle (inheritance), and a changed permissions map must not lock the firewall out of management (lockout guard). These validation failures return 400.
A config upsert or rollback that adds or changes an exception on an inherited rule also requires fw:update:exception on the source firewall that owns that rule, which may be any ancestor. Exceptions already stored on the firewall and left unchanged do not need that permission again, so an unrelated edit is never blocked by an old exception.
Rules and exceptions
Granular alternatives to a full config upsert:
| Method and path | Description | Permission |
|---|---|---|
GET /config/<firewall-id>/rules | This firewall's own rules. Inherited rules are not included | fw:read |
GET /config/<firewall-id>/rules/inherited | Only the rules this firewall inherits, each naming the firewall it comes from. Its own rules are not included | fw:read |
PUT /config/<firewall-id>/rules/{id} | Upsert one rule | fw:update:rule |
DELETE /config/<firewall-id>/rules/{id} | Delete one rule | fw:update:rule |
GET /config/<firewall-id>/exceptions | This firewall's own exceptions. Inherited ones are not included | fw:read |
GET /config/<firewall-id>/exceptions/inherited | Only the exceptions this firewall inherits, each naming the firewall it comes from | fw:read |
PUT /config/<firewall-id>/exceptions/{id} | Upsert one exception. If the rule is inherited, also requires fw:update:exception on its source firewall | fw:update:exception |
DELETE /config/<firewall-id>/exceptions/{id} | Delete one exception | fw:update:exception |
/rules returns rules defined on this firewall; /rules/inherited returns ancestor-owned rules. Both contribute to enforcement. The same rule ID can appear in both lists, which makes an exception for that ID ambiguous. Exceptions are split by ownership in the same way.
Entries from the inherited endpoints carry source fields:
| Field | What it holds |
|---|---|
sourceFirewall | ID of the firewall the entry is defined on |
sourceFirewallName | That firewall's display name |
sourceFirewallVersion | Version of that firewall's config that supplied the entry |
Inherited upstreams use two more fields when a nearer firewall declares the same id:
| Field | What it holds |
|---|---|
overridden | true when this upstream is not in effect |
overriddenBy | ID of the nearer firewall whose upstream is in effect |
Rules from both /rules and /rules/inherited carry two more, which answer "may this caller add an exception to this rule" so a UI can disable the action before anyone fills in a form:
| Field | What it holds |
|---|---|
canAddException | Whether the token making this request may add an exception to this rule |
exceptionDeniedReason | Why not, present only when canAddException is false |
exceptionDeniedReason is one of:
missing_child_permission— the caller lacksfw:update:exceptionon this firewall.missing_owner_permission— the caller has it here but not on the source firewall that owns the rule, which is also required. See permissions.ambiguous_rule_id— this rule's ID appears more than once across the firewall and its parents, so an exception naming it would be ambiguous.
Reading inherited entries needs fw:read on this firewall only. It neither requires nor grants permission on source firewalls.
Rule and exception upserts reject an unparseable version range, an unknown upstreamType value, the legacy selector key internal, or a selector function that does not support the firewall's ecosystem. An exception upsert additionally rejects (400) a rule ID that matches no rule, or more than one rule, across this firewall and its parents. See Share configuration across firewalls for the inheritance model behind all of this.
License sets
Named lists of SPDX license IDs, referenced by license selector rules. See Enforce license policy.
| Method and path | Description | Permission |
|---|---|---|
GET /license-sets | List license sets | none beyond ns:access |
POST /license-sets | Create one (name, description, licenses) | ns:update:licenses |
PUT /license-sets/{licenseSet} | Update | ns:update:licenses |
DELETE /license-sets/{licenseSet} | Delete. 409 while any firewall rule references it | ns:update:licenses |
Logs, metrics, observations, audit
| Method and path | Description |
|---|---|
GET /log | Query firewall log entries, newest first. Params: firewall, user, allUsers, search, limit (default 100, max 1000), before (opaque cursor). Returns {entries, nextCursor}. Defaults to the caller's own entries; see Logs |
GET /log/stream | Server-sent events: last 10 entries, then new ones live. Same params |
GET /metrics | Namespace metrics. Params: periodMinutes (default 1440, max 43200), bucketMinutes (rollup size, max 1440). See Metrics |
GET /metrics/firewall/<firewall-id> | Same shape for one firewall |
GET /observations | Package usage inventory. Params: firewall, period (today, 7d, 30d, 90d), pageSize, pageToken. See Observations |
GET /audit | Audit events. Params: action, resourceType, resourceId, actorUserId, outcome, from, to, limit (max 1000), offset. See Audit log |
Webhooks
Push firewall, audit, configuration, and publish events to your own systems; wire format and delivery behavior in the webhooks reference, setup in Receive webhook events.
| Method and path | Description | Permission |
|---|---|---|
GET /webhooks | List webhooks, secrets redacted | none beyond ns:access |
POST /webhooks | Create (name, description, url, enabled, eventTypes, optional firewalls scope). The 201 response carries the plaintext signing secret | ns:update:webhooks |
GET /webhooks/{webhook} | Detail, secret redacted | none beyond ns:access |
PUT /webhooks/{webhook} | Update configuration; the secret is untouched | ns:update:webhooks |
DELETE /webhooks/{webhook} | Delete the webhook and its buffered events | ns:update:webhooks |
GET /webhooks/{webhook}/secret | The decrypted signing secret, plus the previous secret during its 24-hour rotation window | ns:update:webhooks |
POST /webhooks/{webhook}/rotate-secret | Generate a new secret immediately; the old one keeps verifying for 24 hours | ns:update:webhooks |
POST /webhooks/{webhook}/test | Send one signed test event synchronously, optional body {"type": ...}; returns status, response body, and duration | ns:update:webhooks |
POST /webhooks/{webhook}/unquarantine | Release a quarantined webhook; delivery resumes immediately | ns:update:webhooks |
GET /webhooks/{webhook}/deliveries | Delivery records. Params: limit (default 50, max 128), offset | none beyond ns:access |
GET /webhooks/{webhook}/deliveries/{delivery} | One delivery with full payload and endpoint response | none beyond ns:access |
GET /webhooks/{webhook}/metrics | Delivery metrics. Param periodMinutes (max 10080) | none beyond ns:access |
Tokens and identity
| Method and path | Description | Permission |
|---|---|---|
GET /whoami | The calling identity and its permissions | any |
GET /tokens/personal | List your own Personal Access Tokens | any |
POST /tokens/personal | Create a PAT (name, validForHours, optional permissions, firewalls) | ns:create:pat |
GET /tokens/service | List Service Access Tokens | ns:create:service-token |
POST /tokens/service | Create a SAT (same body shape) | ns:create:service-token |
DELETE /tokens/{token} | Revoke a token by deleting it; it stops validating immediately. Own PAT: always allowed. SAT: ns:create:service-token. Another user's PAT: team:update | see description |
Teams
| Method and path | Description | Permission |
|---|---|---|
GET /teams | List teams | team:read |
POST /teams | Create a team | team:update |
PUT /teams/{team} | Update name, description, permissions | team:update |
DELETE /teams/{team} | Delete a team | team:delete |
GET /teams/{team}/members | List members | team:read |
POST /teams/{team}/members | Add a member | team:update:membership |
DELETE /teams/{team}/members/{userId} | Remove a member | team:update:membership |
Trusted Builders and OIDC
| Method and path | Description | Permission |
|---|---|---|
GET /trusted-builders | List Trusted Builders | ns:create:service-token |
POST /trusted-builders | Register one (name, repositoryOwner, repository, repositoryId, permissions, firewalls, enabled) | ns:create:service-token |
PUT /trusted-builders/{builder} | Update | ns:create:service-token |
DELETE /trusted-builders/{builder} | Delete | ns:create:service-token |
POST /oidc/exchange | Exchange a GitHub OIDC ID token ({"idToken": ...}) for a 15-minute SAT. Unauthenticated | none |
Advisories
| Method and path | Description |
|---|---|
GET /advisories/{purl} | Vulnerability advisories for a package URL |
Related
- Reference: CLI, Firewall config, Tokens, Permissions
- Getting started: GitHub Actions, Config as code