Vault

Store, govern, and resolve secret material — API keys, tokens, passwords, and keys — without ever exposing the secret to the principal that uses it. A namespace is a federated zone; a credential is a governed leaf encrypted at rest. No public endpoint ever returns a secret value: secrets are decrypted only at the internal, server-to-server resolve endpoint, only for exportable credentials, and every resolve is authorized against the acting principal and audited.

Base URL/api/v1/vault

Automation triggers: view every Vault event, payload field, and predicate.

Namespaces

CRUD on namespaces — the federated zone that contains credentials. Creating a namespace mints the IAM zone and grants the creator the full sub-namespace bundle (which already covers creating credentials inside it). All public routes require a JWT and the X-Company-Id header.

POST/api/v1/vault/namespaces

Create Namespace

Create a namespace (mints the federated zone). The creator automatically receives vault:namespaces:* and vault:permissions:namespaces:manage on the new namespace path.

Bearer token required. Header: X-Company-Id. Permission: vault:namespaces:create (granted on org/{company_id}).

Request Body

NameTypeDescription
name*
stringDisplay name (1–200 chars). Unique within the company.
slug
stringURL-safe id (≤ 64 chars), unique within the company. Derived from name when omitted.
description
stringOptional free-text description

Response Fields

NameTypeDescription
id*
string (UUID)Namespace ID
company_id*
string (UUID)Owning organisation
name*
stringDisplay name
slug*
stringURL-safe id
description*
string | nullDescription, or null
allowed_consumer_services*
string[] | nullOptional consumer allow-list (Phase 2). null = open to any eligible principal.
created_by*
string (UUID) | nullPrincipal that created the namespace, or null
created_at*
string (ISO 8601)Creation time
updated_at*
string (ISO 8601)Last update time
curl -X POST https://platform.ergondata.ai/api/v1/vault/namespaces \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Production Integrations",
    "slug": "production-integrations",
    "description": "Third-party API credentials for production."
  }'

Response

201 Created
{
  "id": "9b1f8c2e-4d3a-4f1b-8a7c-2e5d6f7a8b90",
  "company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
  "name": "Production Integrations",
  "slug": "production-integrations",
  "description": "Third-party API credentials for production.",
  "allowed_consumer_services": null,
  "created_by": "u9000000-0000-4000-8000-000000000001",
  "created_at": "2026-04-14T10:30:00Z",
  "updated_at": "2026-04-14T10:30:00Z"
}
GET/api/v1/vault/namespaces

List Namespaces

List namespaces for the company. Results are filtered to the namespaces the caller can view (vault:namespaces:view on the org or on a specific namespace path).

Bearer token required. Header: X-Company-Id. Filtered by vault:namespaces:view.

Response Fields

NameTypeDescription
[]*
Namespace[]Visible namespaces, newest first
curl https://platform.ergondata.ai/api/v1/vault/namespaces \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}"

Response

200 OK
[
  {
    "id": "9b1f8c2e-4d3a-4f1b-8a7c-2e5d6f7a8b90",
    "company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
    "name": "Production Integrations",
    "slug": "production-integrations",
    "description": "Third-party API credentials for production.",
    "allowed_consumer_services": null,
    "created_by": "u9000000-0000-4000-8000-000000000001",
    "created_at": "2026-04-14T10:30:00Z",
    "updated_at": "2026-04-14T10:30:00Z"
  }
]
GET/api/v1/vault/namespaces/{namespace_id}

Get Namespace

Retrieve a single namespace by ID.

Bearer token required. Header: X-Company-Id. Permission: vault:namespaces:view (on the namespace path).

Path Parameters

NameTypeDescription
namespace_id*
string (UUID)Namespace ID

Response Fields

NameTypeDescription
id*
string (UUID)Namespace ID
company_id*
string (UUID)Owning organisation
name*
stringDisplay name
slug*
stringURL-safe id
description*
string | nullDescription, or null
allowed_consumer_services*
string[] | nullConsumer allow-list (Phase 2), or null = open
created_by*
string (UUID) | nullCreator principal, or null
created_at*
string (ISO 8601)Creation time
updated_at*
string (ISO 8601)Last update time
curl https://platform.ergondata.ai/api/v1/vault/namespaces/{namespace_id} \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}"

Response

200 OK
{
  "id": "9b1f8c2e-4d3a-4f1b-8a7c-2e5d6f7a8b90",
  "company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
  "name": "Production Integrations",
  "slug": "production-integrations",
  "description": "Third-party API credentials for production.",
  "allowed_consumer_services": null,
  "created_by": "u9000000-0000-4000-8000-000000000001",
  "created_at": "2026-04-14T10:30:00Z",
  "updated_at": "2026-04-14T10:30:00Z"
}
PATCH/api/v1/vault/namespaces/{namespace_id}

Update Namespace

Update a namespace's name, description, or optional consumer allow-list. Only the supplied fields change.

Bearer token required. Header: X-Company-Id. Permission: vault:namespaces:manage (on the namespace path).

Path Parameters

NameTypeDescription
namespace_id*
string (UUID)Namespace ID

Request Body

NameTypeDescription
name
stringNew display name (1–200 chars)
description
stringNew description
allowed_consumer_services
string[]Optional consumer allow-list (Phase 2). Restricts which services/principal-types may become eligible here; omit or null = open.

Response Fields

NameTypeDescription
id*
string (UUID)Namespace ID
company_id*
string (UUID)Owning organisation
name*
stringDisplay name
slug*
stringURL-safe id
description*
string | nullDescription, or null
allowed_consumer_services*
string[] | nullConsumer allow-list (Phase 2), or null = open
created_by*
string (UUID) | nullCreator principal, or null
created_at*
string (ISO 8601)Creation time
updated_at*
string (ISO 8601)Last update time
curl -X PATCH https://platform.ergondata.ai/api/v1/vault/namespaces/{namespace_id} \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Production-only third-party credentials."
  }'

Response

200 OK
{
  "id": "9b1f8c2e-4d3a-4f1b-8a7c-2e5d6f7a8b90",
  "company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
  "name": "Production Integrations",
  "slug": "production-integrations",
  "description": "Production-only third-party credentials.",
  "allowed_consumer_services": null,
  "created_by": "u9000000-0000-4000-8000-000000000001",
  "created_at": "2026-04-14T10:30:00Z",
  "updated_at": "2026-04-14T11:02:11Z"
}
DELETE/api/v1/vault/namespaces/{namespace_id}

Delete Namespace

Delete a namespace. Cascades to all credentials (and their versions) inside it, and soft-deletes the IAM resource.

Bearer token required. Header: X-Company-Id. Permission: vault:namespaces:delete (on the namespace path).

Path Parameters

NameTypeDescription
namespace_id*
string (UUID)Namespace ID
curl -X DELETE https://platform.ergondata.ai/api/v1/vault/namespaces/{namespace_id} \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}"

Response

204 No Content

Credentials

CRUD on credentials — the governed leaf — inside a namespace. A credential carries a type, a source (supplied or generated), an exportable flag, non-secret config, and (for keypairs) public_material. The secret material is encrypted at rest the moment it is written and lives only as ciphertext. No endpoint in this section ever returns a secret value — not on create, not on read. The value is decrypted only by trusted services through Vault's private internal contract, and only for exportable credentials. Today only source=supplied is accepted; generated material is Preview and returns 501.

POST/api/v1/vault/namespaces/{namespace_id}/credentials

Create Credential

Create a credential inside a namespace. The plaintext material is sealed (envelope-encrypted) immediately and never persisted, logged, or echoed — the response is metadata only. Set exportable=false to make a key that can never be resolved, only operated on (Preview). source=generated is Preview and returns 501; create with source=supplied and provide material.

Bearer token required. Header: X-Company-Id. Permission: vault:namespaces:credentials:create (on the namespace path).

Path Parameters

NameTypeDescription
namespace_id*
string (UUID)Parent namespace ID

Request Body

NameTypeDescription
name*
stringDisplay name (1–200 chars). Unique within the namespace.
slug
stringReference key (≤ 64 chars), unique within the namespace. Derived from name when omitted.
type*
stringCredential type. Supplied types: api_key, bearer_token, basic_auth, oauth2_client_credentials, secret_value, config. Generated types (Preview): random_bytes, password, aes_key, hmac_key, rsa_keypair, ec_keypair, ed25519_keypair, ssh_keypair.
source
stringHow the material came to exist: supplied (you paste it) or generated (Vault generates it — Preview, returns 501).Default: supplied
exportable
booleanWhen true, the value can be resolved via vault:credentials:use. When false, the secret never leaves Vault and can only be operated on (Preview).Default: true
config
objectNon-secret per-type config, e.g. {placement, name} for api_key, {username} for basic_auth, {client_id, token_url, scopes} for oauth2_client_credentials. Never holds the secret.Default: {}
material*
stringThe secret value (plaintext). Required for supplied credentials. Sealed immediately on write; never stored in the clear or returned.

Response Fields

NameTypeDescription
id*
string (UUID)Credential ID
company_id*
string (UUID)Owning organisation
namespace_id*
string (UUID)Parent namespace
name*
stringDisplay name
slug*
stringReference key
type*
stringCredential type
source*
stringsupplied or generated
exportable*
booleanWhether the value can be resolved
config*
objectNon-secret per-type config
public_material*
string | nullNon-secret public half of a keypair (public key / certificate), or null. Never the secret.
last_rotated_at*
string (ISO 8601) | nullWhen the material was last rotated, or null
created_by*
string (UUID) | nullCreator principal, or null
created_at*
string (ISO 8601)Creation time
updated_at*
string (ISO 8601)Last update time
curl -X POST https://platform.ergondata.ai/api/v1/vault/namespaces/{namespace_id}/credentials \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Stripe API Key",
    "type": "api_key",
    "source": "supplied",
    "exportable": true,
    "config": { "placement": "header", "name": "Authorization" },
    "material": "sk_live_51HxxxxxxxxxxxxYOURKEY"
  }'

Response

201 Created
{
  "id": "3a7d9e10-2b4c-4d6e-9f01-2a3b4c5d6e7f",
  "company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
  "namespace_id": "9b1f8c2e-4d3a-4f1b-8a7c-2e5d6f7a8b90",
  "name": "Stripe API Key",
  "slug": "stripe-api-key",
  "type": "api_key",
  "source": "supplied",
  "exportable": true,
  "config": { "placement": "header", "name": "Authorization" },
  "public_material": null,
  "last_rotated_at": null,
  "created_by": "u9000000-0000-4000-8000-000000000001",
  "created_at": "2026-04-14T10:35:00Z",
  "updated_at": "2026-04-14T10:35:00Z"
}
GET/api/v1/vault/namespaces/{namespace_id}/credentials

List Credentials

List credentials in a namespace (metadata only). Results are filtered to the credentials the caller can view. The secret value is never included.

Bearer token required. Header: X-Company-Id. Filtered by vault:credentials:view.

Path Parameters

NameTypeDescription
namespace_id*
string (UUID)Parent namespace ID

Response Fields

NameTypeDescription
[]*
Credential[]Visible credentials (metadata only), newest first
curl https://platform.ergondata.ai/api/v1/vault/namespaces/{namespace_id}/credentials \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}"

Response

200 OK
[
  {
    "id": "3a7d9e10-2b4c-4d6e-9f01-2a3b4c5d6e7f",
    "company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
    "namespace_id": "9b1f8c2e-4d3a-4f1b-8a7c-2e5d6f7a8b90",
    "name": "Stripe API Key",
    "slug": "stripe-api-key",
    "type": "api_key",
    "source": "supplied",
    "exportable": true,
    "config": { "placement": "header", "name": "Authorization" },
    "public_material": null,
    "last_rotated_at": null,
    "created_by": "u9000000-0000-4000-8000-000000000001",
    "created_at": "2026-04-14T10:35:00Z",
    "updated_at": "2026-04-14T10:35:00Z"
  }
]
GET/api/v1/vault/credentials/{credential_id}

Get Credential

Retrieve a credential's metadata — type, config, and public_material (for keypairs). This endpoint never returns the secret value.

Bearer token required. Header: X-Company-Id. Permission: vault:credentials:view (on the credential or its namespace).

Path Parameters

NameTypeDescription
credential_id*
string (UUID)Credential ID

Response Fields

NameTypeDescription
id*
string (UUID)Credential ID
company_id*
string (UUID)Owning organisation
namespace_id*
string (UUID)Parent namespace
name*
stringDisplay name
slug*
stringReference key
type*
stringCredential type
source*
stringsupplied or generated
exportable*
booleanWhether the value can be resolved
config*
objectNon-secret per-type config
public_material*
string | nullPublic half for keypairs, or null. Never the secret.
last_rotated_at*
string (ISO 8601) | nullWhen the material was last rotated, or null
created_by*
string (UUID) | nullCreator principal, or null
created_at*
string (ISO 8601)Creation time
updated_at*
string (ISO 8601)Last update time
curl https://platform.ergondata.ai/api/v1/vault/credentials/{credential_id} \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}"

Response

200 OK
{
  "id": "3a7d9e10-2b4c-4d6e-9f01-2a3b4c5d6e7f",
  "company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
  "namespace_id": "9b1f8c2e-4d3a-4f1b-8a7c-2e5d6f7a8b90",
  "name": "Stripe API Key",
  "slug": "stripe-api-key",
  "type": "api_key",
  "source": "supplied",
  "exportable": true,
  "config": { "placement": "header", "name": "Authorization" },
  "public_material": null,
  "last_rotated_at": null,
  "created_by": "u9000000-0000-4000-8000-000000000001",
  "created_at": "2026-04-14T10:35:00Z",
  "updated_at": "2026-04-14T10:35:00Z"
}
PATCH/api/v1/vault/credentials/{credential_id}

Update Credential

Update a credential's metadata or replace its secret material. Supplying material re-seals the value (envelope-encrypted) and stamps last_rotated_at; the plaintext is never persisted or returned. The response is metadata only.

Bearer token required. Header: X-Company-Id. Permission: vault:credentials:manage (on the credential or its namespace).

Path Parameters

NameTypeDescription
credential_id*
string (UUID)Credential ID

Request Body

NameTypeDescription
name
stringNew display name (1–200 chars)
config
objectReplacement non-secret per-type config
exportable
booleanToggle whether the value can be resolved
material
stringNew secret value (plaintext). When provided, the credential is re-sealed and last_rotated_at is updated. Never stored in the clear or returned.

Response Fields

NameTypeDescription
id*
string (UUID)Credential ID
namespace_id*
string (UUID)Parent namespace
name*
stringDisplay name
type*
stringCredential type
exportable*
booleanWhether the value can be resolved
config*
objectNon-secret per-type config
public_material*
string | nullPublic half for keypairs, or null
last_rotated_at*
string (ISO 8601) | nullUpdated when material is replaced
updated_at*
string (ISO 8601)Last update time
curl -X PATCH https://platform.ergondata.ai/api/v1/vault/credentials/{credential_id} \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}" \
  -H "Content-Type: application/json" \
  -d '{
    "material": "sk_live_51HxxxxxxxxxxxxROTATED"
  }'

Response

200 OK
{
  "id": "3a7d9e10-2b4c-4d6e-9f01-2a3b4c5d6e7f",
  "company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
  "namespace_id": "9b1f8c2e-4d3a-4f1b-8a7c-2e5d6f7a8b90",
  "name": "Stripe API Key",
  "slug": "stripe-api-key",
  "type": "api_key",
  "source": "supplied",
  "exportable": true,
  "config": { "placement": "header", "name": "Authorization" },
  "public_material": null,
  "last_rotated_at": "2026-04-14T12:00:00Z",
  "created_by": "u9000000-0000-4000-8000-000000000001",
  "created_at": "2026-04-14T10:35:00Z",
  "updated_at": "2026-04-14T12:00:00Z"
}
DELETE/api/v1/vault/credentials/{credential_id}

Delete Credential

Delete a credential and its sealed material, and soft-delete the IAM resource.

Bearer token required. Header: X-Company-Id. Permission: vault:credentials:delete (on the credential or its namespace).

Path Parameters

NameTypeDescription
credential_id*
string (UUID)Credential ID
curl -X DELETE https://platform.ergondata.ai/api/v1/vault/credentials/{credential_id} \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}"

Response

204 No Content

Access Audit

Read the audit trail. Every resolve attempt — allow or deny — writes a credential_accesses row, and every namespace/credential mutation writes an activity log. Neither ever exposes a secret value.

GET/api/v1/vault/credentials/{credential_id}/accesses

List Credential Accesses

Who resolved this credential, when, and with what outcome (allow or deny). One row per resolve attempt; the value is never stored or returned.

Bearer token required. Header: X-Company-Id. Permission: vault:credentials:view (on the credential or its namespace).

Path Parameters

NameTypeDescription
credential_id*
string (UUID)Credential ID

Query Parameters

NameTypeDescription
limit
integerResults to return (1–500)Default: 100

Response Fields

NameTypeDescription
[]*
AccessEntry[]Access attempts, newest first
curl "https://platform.ergondata.ai/api/v1/vault/credentials/{credential_id}/accesses?limit=50" \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}"

Response

200 OK
[
  {
    "id": "ac1d0001-0000-4000-8000-000000000001",
    "credential_id": "3a7d9e10-2b4c-4d6e-9f01-2a3b4c5d6e7f",
    "acting_principal_id": "cc110000-0000-4000-8000-000000000009",
    "acting_principal_type": "service",
    "via_service": "compute",
    "action": "use",
    "outcome": "allow",
    "deny_reason": null,
    "accessed_at": "2026-04-14T11:20:05Z"
  },
  {
    "id": "ac1d0002-0000-4000-8000-000000000002",
    "credential_id": "3a7d9e10-2b4c-4d6e-9f01-2a3b4c5d6e7f",
    "acting_principal_id": "a9ent000-0000-4000-8000-000000000003",
    "acting_principal_type": "agent",
    "via_service": "compute",
    "action": "use",
    "outcome": "deny",
    "deny_reason": "use_denied",
    "accessed_at": "2026-04-14T11:18:42Z"
  }
]
GET/api/v1/vault/activity

List Activity

Org-scoped namespace/credential mutation log (created/updated/deleted, resolves). Diffs carry type, non-secret config, and metadata only — never secret material.

Bearer token required. Header: X-Company-Id. Permission: vault:activity:view (granted on org/{company_id}).

Query Parameters

NameTypeDescription
limit
integerResults to return (1–500)Default: 100

Response Fields

NameTypeDescription
[]*
ActivityEntry[]Activity log entries, newest first
curl "https://platform.ergondata.ai/api/v1/vault/activity?limit=50" \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}"

Response

200 OK
[
  {
    "id": "10900001-0000-4000-8000-000000000001",
    "event_type": "vault.credential.created",
    "actor_id": "u9000000-0000-4000-8000-000000000001",
    "actor_type": "member",
    "namespace_id": "9b1f8c2e-4d3a-4f1b-8a7c-2e5d6f7a8b90",
    "credential_id": "3a7d9e10-2b4c-4d6e-9f01-2a3b4c5d6e7f",
    "payload": {
      "credential_id": "3a7d9e10-2b4c-4d6e-9f01-2a3b4c5d6e7f",
      "type": "api_key",
      "source": "supplied",
      "exportable": true,
      "config": { "placement": "header", "name": "Authorization" }
    },
    "created_at": "2026-04-14T10:35:00Z"
  }
]

Access & Connections

Each namespace exposes the platform's standard per-zone access + connection surface under /namespaces/{namespace_id}/access/*. It is the same connect-then-grant protocol used across Ergon: view/create/revoke IAM grants, run the approver inbox for consumer connection requests, and list active inbound connections. Every endpoint here is gated by vault:permissions:namespaces:manage on the namespace, and all grant/connection logic is delegated to IAM — Vault stores no grants of its own.

POST/api/v1/vault/namespaces/access/grants/batch

Create Namespace Access Grants Batch

Create grants across namespace roots in one ordered, partial-success operation. Group a subject with resources and permission UUIDs; operations expand resources first and permission IDs second, to at most 200 grants total. Invalid or unauthorized items fail independently while valid items continue, and partial success returns 200. Whole-request retries are idempotent because existing natural grant tuples return already_exists. A side_effect_error means post-write reconciliation failed but the returned grant exists; retry that item or the whole request to reconcile it. ToolDef slug: vault.namespace_access.create_grants_batch.

Bearer token required. Header: X-Company-Id. Permission: vault:permissions:namespaces:manage on every target namespace root.

Request Body

NameTypeDescription
operations*
array1–200 grouped operations; resources × permission_ids across all operations must expand to at most 200 grants

Response Fields

NameTypeDescription
results*
arrayOne result per expanded grant, ordered by operation, then resource, then permission
summary*
objectOutcome counts
curl -X POST https://platform.ergondata.ai/api/v1/vault/namespaces/access/grants/batch \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}" \
  -H "Content-Type: application/json" \
  -d '{"operations":[{"client_ref":"consumers","principal_type":"workflow","principal_id":"{principal_id}","resources":["org/{company_id}/namespace/{namespace_id}/credential/{credential_id}"],"permission_ids":["{permission_id}"],"effect":"allow"}]}'

Response

200 OK
{
  "results": [{
    "index": 0,
    "client_ref": "consumers",
    "status": "created",
    "principal_type": "workflow",
    "principal_id": "{principal_id}",
    "permission_id": "{permission_id}",
    "resource": "org/{company_id}/namespace/{namespace_id}/credential/{credential_id}",
    "effect": "allow",
    "grant": {"id": "{grant_id}", "permission_id": "{permission_id}", "name": "vault:credentials:use", "resource": "org/{company_id}/namespace/{namespace_id}/credential/{credential_id}", "effect": "allow", "is_system": false, "granted_at": "2026-07-15T16:30:00Z"},
    "error_status": null,
    "error_detail": null,
    "side_effect_error_status": null,
    "side_effect_error_detail": null
  }],
  "summary": {"created": 1, "already_exists": 0, "failed": 0}
}
GET/api/v1/vault/namespaces/{namespace_id}/access/grants

List Grants

List the IAM grants scoped to this namespace (and its credentials), paginated.

Bearer token required. Header: X-Company-Id. Permission: vault:permissions:namespaces:manage (on the namespace path).

Path Parameters

NameTypeDescription
namespace_id*
string (UUID)Namespace ID

Query Parameters

NameTypeDescription
page
integerPage number (≥ 1)Default: 1
limit
integerPage size (1–500)Default: 100

Response Fields

NameTypeDescription
items*
GrantEntry[]Grants on this namespace
total*
integerTotal grants
page*
integerPage returned
limit*
integerPage size used
curl "https://platform.ergondata.ai/api/v1/vault/namespaces/{namespace_id}/access/grants?limit=50" \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}"

Response

200 OK
{
  "items": [
    {
      "id": "9ra0t000-0000-4000-8000-000000000001",
      "principal_type": "service",
      "principal_id": "cc110000-0000-4000-8000-000000000009",
      "principal_label": "Billing Sync Collection",
      "permission_id": "perm_vault_credentials_use",
      "permission_name": "vault:credentials:use",
      "resource": "org/c0ffee00-cafe-babe-dead-beefcafebabe/namespace/9b1f8c2e-4d3a-4f1b-8a7c-2e5d6f7a8b90/credential/3a7d9e10-2b4c-4d6e-9f01-2a3b4c5d6e7f",
      "effect": "allow",
      "granted_at": "2026-04-14T11:00:00Z"
    }
  ],
  "total": 1,
  "page": 1,
  "limit": 50
}
POST/api/v1/vault/namespaces/{namespace_id}/access/grants

Create Grant

Grant a permission to a principal, scoped to this namespace or one of its credentials. Only namespace-grantable Vault permissions are accepted (e.g. vault:credentials:use, vault:credentials:view); the resource must be scoped under the namespace.

Bearer token required. Header: X-Company-Id. Permission: vault:permissions:namespaces:manage (on the namespace path).

Path Parameters

NameTypeDescription
namespace_id*
string (UUID)Namespace ID

Request Body

NameTypeDescription
principal_type*
stringmember, api_key, agent, role, team, automation, or workflow
principal_id*
stringID of the principal receiving the grant
permission_id*
stringPermission to grant (must be grantable from a namespace)
resource
stringResource path to scope the grant to. Defaults to the namespace path; must be scoped under it (e.g. a specific credential).
effect
stringallow or denyDefault: allow

Response Fields

NameTypeDescription
id*
stringNew grant ID
permission_id*
stringPermission granted
name*
stringPermission name
resource*
stringScoped resource
effect*
stringallow or deny
is_system*
booleanWhether this is a system grant
granted_at*
string (ISO 8601)When the grant was created
curl -X POST https://platform.ergondata.ai/api/v1/vault/namespaces/{namespace_id}/access/grants \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}" \
  -H "Content-Type: application/json" \
  -d '{
    "principal_type": "service",
    "principal_id": "{principal_id}",
    "permission_id": "{permission_id}",
    "resource": "org/{company_id}/namespace/{namespace_id}/credential/{credential_id}",
    "effect": "allow"
  }'

Response

201 Created
{
  "id": "9ra0t000-0000-4000-8000-000000000001",
  "permission_id": "perm_vault_credentials_use",
  "name": "vault:credentials:use",
  "resource": "org/c0ffee00-cafe-babe-dead-beefcafebabe/namespace/9b1f8c2e-4d3a-4f1b-8a7c-2e5d6f7a8b90/credential/3a7d9e10-2b4c-4d6e-9f01-2a3b4c5d6e7f",
  "effect": "allow",
  "is_system": false,
  "granted_at": "2026-04-14T11:00:00Z"
}
DELETE/api/v1/vault/namespaces/{namespace_id}/access/grants/{grant_id}

Revoke Grant

Revoke a previously created grant on this namespace.

Bearer token required. Header: X-Company-Id. Permission: vault:permissions:namespaces:manage (on the namespace path).

Path Parameters

NameTypeDescription
namespace_id*
string (UUID)Namespace ID
grant_id*
stringGrant ID to revoke
curl -X DELETE https://platform.ergondata.ai/api/v1/vault/namespaces/{namespace_id}/access/grants/{grant_id} \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}"

Response

204 No Content
GET/api/v1/vault/namespaces/{namespace_id}/access/connection-requests

List Connection Requests

The approver inbox: connection requests raised by consumers that want to use this namespace. Filter by status (defaults to pending).

Bearer token required. Header: X-Company-Id. Permission: vault:permissions:namespaces:manage (on the namespace path).

Path Parameters

NameTypeDescription
namespace_id*
string (UUID)Namespace ID

Query Parameters

NameTypeDescription
status
stringFilter by status: pending, approved, rejectedDefault: pending

Response Fields

NameTypeDescription
[]*
ConnectionRequestEntry[]Connection requests targeting this namespace
curl "https://platform.ergondata.ai/api/v1/vault/namespaces/{namespace_id}/access/connection-requests?status=pending" \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}"

Response

200 OK
[
  {
    "id": "c0nr0001-0000-4000-8000-000000000001",
    "principal_id": "cc110000-0000-4000-8000-000000000009",
    "principal_label": "Billing Sync Collection",
    "direction": "inbound",
    "target_service": "vault",
    "target_resource": "org/c0ffee00-cafe-babe-dead-beefcafebabe/namespace/9b1f8c2e-4d3a-4f1b-8a7c-2e5d6f7a8b90",
    "requested_by": "u9000000-0000-4000-8000-000000000002",
    "requested_permissions": ["vault:credentials:use"],
    "message": "Need to read the Stripe key for the billing sync.",
    "status": "pending",
    "connection_id": null,
    "decided_by": null,
    "decided_at": null,
    "created_at": "2026-04-14T10:55:00Z"
  }
]
POST/api/v1/vault/namespaces/{namespace_id}/access/connection-requests/{request_id}/approve

Approve Connection Request

Approve a consumer's connection request. Optionally narrow the granted permissions (each must be grantable from a namespace) and set a connection label. This connects the principal and, when grant is true, issues the requested use grant.

Bearer token required. Header: X-Company-Id. Permission: vault:permissions:namespaces:manage (on the namespace path).

Path Parameters

NameTypeDescription
namespace_id*
string (UUID)Namespace ID
request_id*
stringConnection request ID

Request Body

NameTypeDescription
permissions
string[]Override the permissions to grant. Defaults to the request's requested_permissions. Each must be grantable from a namespace.
grant
booleanWhether to issue the grant on approvalDefault: true
label
stringOptional label for the resulting connection

Response Fields

NameTypeDescription
id*
stringRequest ID
status*
stringapproved
connection_id
string | nullID of the connection created on approval
decided_by
string | nullApprover principal
decided_at
string (ISO 8601) | nullWhen it was approved
curl -X POST https://platform.ergondata.ai/api/v1/vault/namespaces/{namespace_id}/access/connection-requests/{request_id}/approve \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}" \
  -H "Content-Type: application/json" \
  -d '{
    "permissions": ["vault:credentials:use"],
    "grant": true,
    "label": "Billing Sync"
  }'

Response

200 OK
{
  "id": "c0nr0001-0000-4000-8000-000000000001",
  "principal_id": "cc110000-0000-4000-8000-000000000009",
  "principal_label": "Billing Sync Collection",
  "direction": "inbound",
  "target_service": "vault",
  "target_resource": "org/c0ffee00-cafe-babe-dead-beefcafebabe/namespace/9b1f8c2e-4d3a-4f1b-8a7c-2e5d6f7a8b90",
  "requested_permissions": ["vault:credentials:use"],
  "message": "Need to read the Stripe key for the billing sync.",
  "status": "approved",
  "connection_id": "c0nn0001-0000-4000-8000-000000000007",
  "decided_by": "u9000000-0000-4000-8000-000000000001",
  "decided_at": "2026-04-14T11:00:00Z",
  "created_at": "2026-04-14T10:55:00Z"
}
GET/api/v1/vault/namespaces/{namespace_id}/access/connections

List Connections

List the active inbound connections to this namespace — the principals that have been connected and granted access.

Bearer token required. Header: X-Company-Id. Permission: vault:permissions:namespaces:manage (on the namespace path).

Path Parameters

NameTypeDescription
namespace_id*
string (UUID)Namespace ID

Response Fields

NameTypeDescription
[]*
InboundConnectionEntry[]Active inbound connections to this namespace
curl https://platform.ergondata.ai/api/v1/vault/namespaces/{namespace_id}/access/connections \
  -H "Authorization: Bearer {token}" \
  -H "X-Company-Id: {company_id}"

Response

200 OK
[
  {
    "connection_id": "c0nn0001-0000-4000-8000-000000000007",
    "principal_id": "cc110000-0000-4000-8000-000000000009",
    "principal_label": "Billing Sync Collection",
    "target_service": "vault",
    "target_resource": "org/c0ffee00-cafe-babe-dead-beefcafebabe/namespace/9b1f8c2e-4d3a-4f1b-8a7c-2e5d6f7a8b90",
    "status": "active",
    "created_at": "2026-04-14T11:00:00Z"
  }
]
GET/api/v1/vault/namespaces/{namespace_id}/access/eligible

List Eligible Principals

List principals that are eligible to receive grants in this namespace after applying the connection gate and namespace consumer policy.

Bearer token required. Header: X-Company-Id. Permission: vault:permissions:namespaces:manage (on the namespace path).

Path Parameters

NameTypeDescription
namespace_id*
string (UUID)Namespace ID
curl https://platform.ergondata.ai/api/v1/vault/namespaces/{namespace_id}/access/eligible \
  -H "Authorization: Bearer {token}" -H "X-Company-Id: {company_id}"

Response

200 OK
[]
GET/api/v1/vault/namespaces/{namespace_id}/access/permissions

List Namespace Permissions

List Vault permissions that can be granted from the namespace access surface. Use the returned UUID as permission_id when creating a grant.

Bearer token required. Header: X-Company-Id. Permission: vault:permissions:namespaces:manage (on the namespace path).

Path Parameters

NameTypeDescription
namespace_id*
string (UUID)Namespace ID
curl https://platform.ergondata.ai/api/v1/vault/namespaces/{namespace_id}/access/permissions \
  -H "Authorization: Bearer {token}" -H "X-Company-Id: {company_id}"

Response

200 OK
[]
GET/api/v1/vault/namespaces/{namespace_id}/access/resource-types

Get Namespace Resource Types

Return the namespace-to-credential resource-type chain plus the grantable permissions used by generic access clients.

Bearer token required. Header: X-Company-Id. Permission: vault:permissions:namespaces:manage (on the namespace path).

Path Parameters

NameTypeDescription
namespace_id*
string (UUID)Namespace ID
curl https://platform.ergondata.ai/api/v1/vault/namespaces/{namespace_id}/access/resource-types \
  -H "Authorization: Bearer {token}" -H "X-Company-Id: {company_id}"

Response

200 OK
{ "chain": [], "permissions": [] }
POST/api/v1/vault/namespaces/{namespace_id}/access/connection-requests/{request_id}/reject

Reject Connection Request

Reject a pending inbound connection request for this namespace.

Bearer token required. Header: X-Company-Id. Permission: vault:permissions:namespaces:manage (on the namespace path).

Path Parameters

NameTypeDescription
namespace_id*
string (UUID)Namespace ID
request_id*
stringConnection request ID

Request Body

NameTypeDescription
reason
string | nullOptional rejection reason
curl -X POST https://platform.ergondata.ai/api/v1/vault/namespaces/{namespace_id}/access/connection-requests/{request_id}/reject \
  -H "Authorization: Bearer {token}" -H "X-Company-Id: {company_id}" \
  -H "Content-Type: application/json" -d '{"reason":"Not approved"}'

Response

200 OK
{ "id": "{request_id}", "status": "rejected" }
DELETE/api/v1/vault/namespaces/{namespace_id}/access/connections/{connection_id}

Revoke Connection

Revoke an active inbound namespace connection and its associated access relationship.

Bearer token required. Header: X-Company-Id. Permission: vault:permissions:namespaces:manage (on the namespace path).

Path Parameters

NameTypeDescription
namespace_id*
string (UUID)Namespace ID
connection_id*
stringConnection ID
curl -X DELETE https://platform.ergondata.ai/api/v1/vault/namespaces/{namespace_id}/access/connections/{connection_id} \
  -H "Authorization: Bearer {token}" -H "X-Company-Id: {company_id}"

Response

204 No Content