Skip to main content

Secrets

Endpoints for managing the Secrets an Assistant uses. A Secret is a named credential (an API key, token, or other value) that an Assistant references when running a Skill. Each Secret has a key (its name) and an encrypted value.

Every route on this page is gated by ai.verify (AI must be enabled on the tenant AND the caller must have AI access). The host Assistant is resolved by assistant.lookup(params.id) through the read_access scope, so a missing or inaccessible Assistant answers 404. The three mutating routes (POST, PUT, DELETE) additionally require permission.assistant.write on the Assistant.

Secret values are write-only

A Secret's value is encrypted at rest and is never returned in any response. toHal strips the field entirely, so responses carry the key but omit value altogether. There is no masked placeholder; the field is simply absent. Only the Assistant can use the plaintext value, during Skill execution.

GET /api/assistants/{id}/secrets

List an Assistant's Secrets.

Authentication: Required (AI access via ai.verify)

Pre-blocks: assistant.lookup(params.id)

Response:

A HAL collection under _embedded["inf:assistant-secret"]. Each entry serializes its key but not its value.

List an assistant’s secretsGET /api/assistants/admin:order-desk-assistant/secrets
GET /api/assistants/{id}/secrets is a HAL collection embedding inf:assistant-secret. Each secret serializes its `key` but NEVER its `value`: the encrypted value is stripped by toHal (there is no masked field, the key is simply absent). Requires AI access (ai.verify).
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/admin%3Aorder-desk-assistant/secrets"
}
},
"start": 0,
"count": 2,
"total": 2,
"_embedded": {
"inf:assistant-secret": [
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/admin%3Aorder-desk-assistant/secrets/00000000-0000-4000-8000-000000000001"
}
},
"id": "00000000-0000-4000-8000-000000000001",
"key": "HUBSPOT_API_KEY",
"assistantId": "00000000-0000-4000-8000-000000000002",
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme"
},
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/admin%3Aorder-desk-assistant/secrets/00000000-0000-4000-8000-000000000003"
}
},
"id": "00000000-0000-4000-8000-000000000003",
"key": "SCRATCH_TOKEN",
"assistantId": "00000000-0000-4000-8000-000000000002",
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme"
}
]
}
}
Captured from the API examples test suite; ids and timestamps are normalized.

Secret properties:

FieldTypeDescription
idstring (UUID)Secret id
keystringSecret name (e.g. HUBSPOT_API_KEY)
assistantIdstring (UUID)Id of the owning Assistant
createdAt / updatedAtdateTimestamps

POST /api/assistants/{id}/secrets

Add a Secret to an Assistant.

Authentication: Required (AI access via ai.verify)

Pre-blocks: assistant.lookup(params.id), permission.assistant.write

Request Body:

FieldTypeRequiredDescription
keystringYesSecret name (e.g. SLACK_BOT_TOKEN)
valuestring | nullNoSecret value; encrypted at rest and never echoed back

There is no name or description field. The credential name is key.

Example Request:

{
"key": "SLACK_BOT_TOKEN",
"value": "xoxb-example-token"
}

Response:

Responds 201 Created with the new Secret (value stripped) and a Location header to it.

Add a secret to an assistantPOST /api/assistants/admin:order-desk-assistant/secrets
POST payload is { key (required), value (string|null) } — the field is `key`, not `name`, and there is no `description`. The value is encrypted at rest and never echoed back (toHal strips it). Requires AI access plus permission.assistant.write. Responds 201 with a Location header to the new secret.
Request body
{
"key": "SLACK_BOT_TOKEN",
"value": "xoxb-example-token"
}
Response · 201
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/admin%3Aorder-desk-assistant/secrets/00000000-0000-4000-8000-000000000001"
}
},
"id": "00000000-0000-4000-8000-000000000001",
"tenant": "acme",
"assistantId": "00000000-0000-4000-8000-000000000002",
"key": "SLACK_BOT_TOKEN",
"updatedAt": "2026-01-15T16:20:00.000Z",
"createdAt": "2026-01-15T16:20:00.000Z"
}
Captured from the API examples test suite; ids and timestamps are normalized.

GET /api/assistants/{id}/secrets/{secretId}

Retrieve a single Secret.

Authentication: Required (AI access via ai.verify)

Pre-blocks: assistant.lookup(params.id), Secret lookup (db.lookup)

Response:

The Secret with its value stripped. A missing or inaccessible secretId answers 404.

Get a secretGET /api/assistants/admin:order-desk-assistant/secrets/00000000-0000-4000-8000-000000000001
GET /api/assistants/{id}/secrets/{secretId} returns the single secret (db.lookup) with its `value` stripped by toHal. A missing or inaccessible secretId 404s.
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/admin%3Aorder-desk-assistant/secrets/00000000-0000-4000-8000-000000000001"
}
},
"id": "00000000-0000-4000-8000-000000000001",
"key": "SLACK_BOT_TOKEN",
"assistantId": "00000000-0000-4000-8000-000000000002",
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme"
}
Captured from the API examples test suite; ids and timestamps are normalized.

PUT /api/assistants/{id}/secrets/{secretId}

Update a Secret.

Authentication: Required (AI access via ai.verify)

Pre-blocks: assistant.lookup(params.id), Secret lookup, permission.assistant.write

Request Body:

FieldTypeDescription
keystringRename the Secret
valuestring | nullRotate the value; null or "" clears it. Re-encrypted on update

Example Request:

{
"key": "SLACK_BOT_TOKEN",
"value": "xoxb-rotated-token"
}

Response:

Responds 200 with the updated Secret (value stripped). Runs in a database transaction.

Update a secretPUT /api/assistants/admin:order-desk-assistant/secrets/00000000-0000-4000-8000-000000000001
PUT payload is { key?, value? } (value allows null/empty to clear). On update the new value is re-encrypted by the beforeUpdate hook. Runs in a DB transaction; requires permission.assistant.write. Returns the updated secret with `value` stripped.
Request body
{
"key": "SLACK_BOT_TOKEN",
"value": "xoxb-rotated-token"
}
Response · 200
{
"_links": {
"self": {
"href": "https://informer.example.com/api/assistants/admin%3Aorder-desk-assistant/secrets/00000000-0000-4000-8000-000000000001"
}
},
"id": "00000000-0000-4000-8000-000000000001",
"key": "SLACK_BOT_TOKEN",
"assistantId": "00000000-0000-4000-8000-000000000002",
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme"
}
Captured from the API examples test suite; ids and timestamps are normalized.

DELETE /api/assistants/{id}/secrets/{secretId}

Delete a Secret.

Authentication: Required (AI access via ai.verify)

Pre-blocks: assistant.lookup(params.id), Secret lookup, permission.assistant.write

Response:

Responds 200 with an empty body (Informer convention), not 204. Runs in a database transaction.

Delete a secretDELETE /api/assistants/admin:order-desk-assistant/secrets/00000000-0000-4000-8000-000000000001
DELETE /api/assistants/{id}/secrets/{secretId} removes the secret (db.remove) within a transaction; requires permission.assistant.write. Returns 200 with an EMPTY body (Informer convention), NOT 204.
Response · 200 · no body
Captured from the API examples test suite; ids and timestamps are normalized.

Security Considerations

Encryption

  • Secret values are encrypted at rest by the model's beforeCreate and beforeUpdate hooks.
  • The plaintext value is never serialized in any response; only the Assistant can read it during Skill execution.

Access Control

  • All Secret routes require AI access (ai.verify).
  • Creating, updating, and deleting Secrets requires permission.assistant.write on the owning Assistant.
  • Secrets are isolated per Assistant.

Best Practices

  • Use descriptive keys (e.g. GITHUB_TOKEN, STRIPE_SECRET_KEY).
  • Rotate values periodically with a PUT.
  • Delete unused Secrets.
  • Never hardcode Secrets in instructions or Skill configurations.