Integration configuration
The integration-configuration endpoints let an org admin list which integrations are activated, set or rotate their credentials, and deactivate them — from a script, automation, or AI agent. Common use cases:
- IT provisioning script activates Salesforce on a fresh Phoenix org.
- Quarterly key rotation updates the HG Insights v2 key when the partner rotates their secret.
- Decommissioning removes a credential when an integration is no longer needed.
All operations require an admin-scoped API key.
User-scoped keys receive 403 forbidden_admin_scope on every endpoint
and tool listed here.
Activation model
An integration is active when the per-tenant
configured_integrations table has a row for its key. There is no
separate is_active column. This means:
- Setting credentials activates the integration.
- Rotating credentials (PUT on a key that already has a row) is an upsert — the integration stays active across the rotation, no intermediate down state.
- Deleting credentials deactivates the integration immediately.
The audit log tells activation and rotation apart: every
set_integration_credentials row records metadata.wasUpdate: false
on first set and true on subsequent rotations.
Surfaces
The same three operations are exposed three ways:
| Surface | Path / tool name | Auth |
|---|---|---|
| REST (admin facade) | GET /api/admin/integrations, PUT /api/admin/integrations/{key}/credentials, DELETE /api/admin/integrations/{key}/credentials | Authorization: Bearer <admin_key> or x-api-key |
| MCP tools | admin_list_integrations, admin_set_integration_credentials, admin_remove_integration_credentials | Admin-scoped API key over /api/mcp (Bearer) or /api/ai/{key}/mcp |
| Power Automate REST facade | POST /api/powerautomate/admin_list_integrations (etc.) | Authorization: Bearer <admin_key> |
Underlying business logic is the same across all three surfaces — see
webapp/src/server/api/admin/integration-management.ts.
Security: credentials never leave configured_integrations
The credential value is taken in on PUT, persisted to the
configured_integrations.value column, and never echoed back in any
API response. It also never appears in the MCP metering table — the
admin_set_integration_credentials tool declares value as a sensitive
parameter, and the metering layer redacts it to the literal string
'<redacted>' before persisting telemetry.
Concretely, if you call admin_set_integration_credentials with
value: "phx-secret-key-abc123", you can grep
webapp_tool_metering.metadata and webapp_org_admin_audit_log.metadata
all you like — the plaintext string is never there.
Org isolation
The organization is always derived from the API key
(webapp_api_keys_registry.organization_slug). It is never accepted
from the request body, query, or path. An admin key for org A cannot
read or modify org B's integrations.
Auditing
Every operation writes a row to webapp_org_admin_audit_log:
list_integrations—target_type=null, target_id=null, metadata={count, configuredCount}. The list response reveals which integrations the org has activated, which is itself sensitive — that's why reads are audited.set_integration_credentials—target_type='integration', target_id=<key>, metadata={wasUpdate: boolean}.wasUpdate=trueis a rotation;falseis an activation.remove_integration_credentials—target_type='integration', target_id=<key>, metadata={wasNoop: boolean}.wasNoop=falsemeans a row was actually deleted;truemeans the DELETE was idempotent (no-op).
Polling note: because
list_integrationsis audited, polling the list endpoint at high frequency will fill the audit log. If your automation needs frequent reads, either cache the response client-side or add a debouncing layer. We do not throttle in code — the choice is yours.
GET /api/admin/integrations
List the integration catalog joined with this org's configuration state. Returns metadata only — credential values are never included.
Request
GET /api/admin/integrations
Authorization: Bearer phx_<your-admin-key>
Response (200)
{
"integrations": [
{
"key": "hginsights_v2",
"name": "HG Insights v2",
"description": "Unified API for technographic, firmographic, and intent data.",
"isConfigured": true,
"hasCredentials": true,
"configuredAt": "2026-04-15T10:30:00.000Z",
"updatedAt": "2026-04-29T14:00:00.000Z",
"configuredByEmail": "alice@acme.com"
},
{
"key": "salesforce",
"name": "Salesforce",
"description": "CRM integration",
"isConfigured": false,
"hasCredentials": false,
"configuredAt": null,
"updatedAt": null,
"configuredByEmail": null
}
]
}
hasCredentials aliases isConfigured for clarity in API responses
(presence-of-credentials = active per the model above).
configuredByEmail is null when the integration is not configured or
when the user who originally configured it no longer exists.
Errors
403 forbidden_admin_scope— caller's API key is not admin-scoped.
PUT /api/admin/integrations/{key}/credentials
Set or rotate the credential for an integration. Upserts the
configured_integrations row. Activation if no row existed; rotation
if it did.
Request
PUT /api/admin/integrations/hginsights_v2/credentials
Authorization: Bearer phx_<your-admin-key>
Content-Type: application/json
{
"value": "your-hg-v2-api-key"
}
Response (200)
{
"key": "hginsights_v2",
"isConfigured": true,
"hasCredentials": true,
"updatedAt": "2026-04-29T14:00:00.000Z"
}
The value is not echoed back.
Errors
400 invalid_request— body is not valid JSON or missing/oversizevalue.400 integration_disabled— the integration is in the catalog but disabled at the platform level.400 invalid_credentials— a registered validator rejected the value (e.g., upstream API returned 401 with the new key). The existing row is left intact.403 forbidden_admin_scope— caller's API key is not admin-scoped.404 integration_not_found—{key}does not exist in the catalog.500 tool_setup_failed— credential saved, but a downstream tool-setup step (e.g., TrustRadius aggregator wiring) failed. Retry the same call.
Example: rotate the HG Insights v2 key
curl -X PUT https://phoenix.hginsights.com/api/admin/integrations/hginsights_v2/credentials \
-H "Authorization: Bearer phx_admin_xxx" \
-H "Content-Type: application/json" \
-d '{"value": "your-new-hg-v2-key"}'
{
"key": "hginsights_v2",
"isConfigured": true,
"hasCredentials": true,
"updatedAt": "2026-04-29T14:00:00.000Z"
}
The agent service reads the v2 key per request through the Phoenix MCP client — there is no caching beyond the request scope, so the next agent run uses the new key.
DELETE /api/admin/integrations/{key}/credentials
Deactivate an integration by removing its credential. Idempotent —
returns 200 whether or not a row existed. This avoids hostile retries
on automation jobs that have already succeeded.
Request
DELETE /api/admin/integrations/zoominfo/credentials
Authorization: Bearer phx_<your-admin-key>
Response (200)
{
"key": "zoominfo",
"isConfigured": false
}
Errors
403 forbidden_admin_scope— caller's API key is not admin-scoped.404 integration_not_found—{key}does not exist in the catalog at all (this is not the same as "no credential exists" — that case returns 200).
Both calls are audited; the second returns the same payload but writes
metadata.wasNoop: true so the audit trail stays truthful about caller
intent.
MCP tool inputs
The MCP tools take the same fields as the REST endpoints, except
integration_key is the parameter name (snake_case) instead of a path
segment:
| Tool | Input | Notes |
|---|---|---|
admin_list_integrations | {} | No parameters. |
admin_set_integration_credentials | { "integration_key": string, "value": string } | value is redacted from telemetry. |
admin_remove_integration_credentials | { "integration_key": string } | Idempotent. |
See the MCP tools reference for full per-tool docs.
Validators (future-facing)
Some integrations will eventually register a server-side validator that
the PUT endpoint runs before persisting. When a validator rejects, the
endpoint returns 400 invalid_credentials with the validator's
message — and the existing row stays intact. Today the validator
registry is empty, mirroring the current webapp behavior. New
validators ship in subsequent issues.
Skill / runbook
For day-to-day operational notes (when to rotate, who to notify, common mistakes), see the admin-api-keys runbook.