Skip to main content

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:

SurfacePath / tool nameAuth
REST (admin facade)GET /api/admin/integrations, PUT /api/admin/integrations/{key}/credentials, DELETE /api/admin/integrations/{key}/credentialsAuthorization: Bearer <admin_key> or x-api-key
MCP toolsadmin_list_integrations, admin_set_integration_credentials, admin_remove_integration_credentialsAdmin-scoped API key over /api/mcp (Bearer) or /api/ai/{key}/mcp
Power Automate REST facadePOST /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_integrationstarget_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_credentialstarget_type='integration', target_id=<key>, metadata={wasUpdate: boolean}. wasUpdate=true is a rotation; false is an activation.
  • remove_integration_credentialstarget_type='integration', target_id=<key>, metadata={wasNoop: boolean}. wasNoop=false means a row was actually deleted; true means the DELETE was idempotent (no-op).

Polling note: because list_integrations is 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/oversize value.
  • 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:

ToolInputNotes
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.