Managing Integrations
Overview
An integration is a configured connection between your tenant and an external provider. You supply credentials once, choose which capabilities to enable, and the platform handles verification, encryption, and routing from that point forward. Each provider can have at most one integration per tenant - if you need to swap credentials, update the existing record rather than creating a new one.
Provider credentials are encrypted at rest and never returned in plaintext through the API. Sensitive fields such as secret keys and auth tokens are always masked in responses, so you can safely log or display integration details without exposing credentials. Non-sensitive fields such as publishable keys and sender phone numbers remain visible to help you identify which account is configured.
Integration Lifecycle
| Status | Description | How to Transition |
|---|---|---|
| pending_verify | Credential check queued but not yet complete | Automatic - transitions after async verification |
| active | Verified, healthy, and eligible for routing | Automatic after successful verification; or POST /{id}/activate |
| inactive | Manually disabled, excluded from routing | POST /{id}/disable; reverse with POST /{id}/activate |
| error | Verification failed or a runtime error was recorded | Update credentials via PATCH /{id} to re-trigger verification |
Routing and Status
Routing rules only select integrations in active status. An integration in pending_verify, inactive, or error will not receive operations even if a routing rule references it.
API Endpoints
List Available Providers
Returns all providers registered in the platform, including their supported capabilities, the credential fields required to configure them, and whether your tenant has already configured each one.
Endpoint: GET /api/v1/integrations/providers
Authentication: Required (Bearer token)
Response (200 OK):
{
"success": true,
"message": "Providers retrieved successfully",
"data": [
{
"name": "stripe",
"display_name": "Stripe",
"category": "payment",
"capabilities": ["initiate_payment", "process_refund", "verify_payment"],
"credential_schema": {
"publishable_key": { "type": "string", "sensitive": false, "required": true },
"secret_key": { "type": "string", "sensitive": true, "required": true },
"webhook_secret": { "type": "string", "sensitive": true, "required": false }
},
"is_configured": false
},
{
"name": "twilio",
"display_name": "Twilio",
"category": "communication",
"capabilities": ["send_sms", "send_whatsapp"],
"credential_schema": {
"account_sid": { "type": "string", "sensitive": false, "required": true },
"auth_token": { "type": "string", "sensitive": true, "required": true },
"from_number": { "type": "string", "sensitive": false, "required": true }
},
"is_configured": true
}
],
"meta": {}
}Use credential_schema to build your configuration form. Fields marked sensitive: true are encrypted on the server and masked in subsequent API responses.
List Integrations
Returns all integrations configured for your tenant. Supports filtering and pagination.
Endpoint: GET /api/v1/integrations
Authentication: Required (Bearer token)
Query Parameters:
status(string) - Filter by status:pending_verify,active,inactive,errorcategory(string) - Filter by category:payment,communicationper_page(integer) - Results per page (default: 25, max: 100)page(integer) - Page number
Example Request:
GET /api/v1/integrations?status=active&category=payment&per_page=15Response (200 OK):
{
"success": true,
"data": [
{
"id": "01hwxyz123abc456def789ghi0",
"provider": "stripe",
"display_name": "Stripe",
"category": "payment",
"status": "active",
"enabled_capabilities": ["initiate_payment", "process_refund", "verify_payment"],
"credentials": {
"publishable_key": "pk_test_placeholder",
"secret_key": null,
"webhook_secret": null
},
"metadata": {},
"verified_at": "2026-01-10T08:45:00Z",
"created_at": "2026-01-10T08:30:00Z",
"updated_at": "2026-01-10T08:45:00Z"
}
],
"meta": {
"current_page": 1,
"per_page": 15,
"total": 3,
"last_page": 1
},
"links": {
"first": "/api/v1/integrations?page=1",
"last": "/api/v1/integrations?page=1",
"prev": null,
"next": null
}
}Configure an Integration
Creates a new integration for the specified provider. Triggers async credential verification immediately - the integration will be in pending_verify status until verification completes.
Endpoint: POST /api/v1/integrations
Authentication: Required (Bearer token)
Request Body:
{
"provider": "stripe",
"credentials": {
"publishable_key": "pk_test_placeholder",
"secret_key": "sk_test_placeholder",
"webhook_secret": "whsec_placeholder"
},
"enabled_capabilities": ["initiate_payment", "process_refund", "verify_payment"],
"metadata": {
"environment": "production",
"account_label": "Primary Stripe Account"
}
}Required Fields:
provider- Provider name fromGET /providers(e.g.,stripe,twilio)credentials- Object matching the provider'scredential_schemaenabled_capabilities- Array of capability names to activate; must be a subset of the provider's supported capabilities
Optional Fields:
metadata- Arbitrary key-value object for your own reference (environment labels, account notes, etc.)
Response (201 Created):
{
"success": true,
"message": "Integration configured successfully",
"data": {
"id": "01hwxyz123abc456def789ghi0",
"provider": "stripe",
"display_name": "Stripe",
"category": "payment",
"status": "pending_verify",
"enabled_capabilities": ["initiate_payment", "process_refund", "verify_payment"],
"credentials": {
"publishable_key": "pk_test_placeholder",
"secret_key": null,
"webhook_secret": null
},
"metadata": {
"environment": "production",
"account_label": "Primary Stripe Account"
},
"verified_at": null,
"created_at": "2026-01-10T08:30:00Z",
"updated_at": "2026-01-10T08:30:00Z"
},
"meta": {}
}Error Response (422 Unprocessable Entity):
{
"success": false,
"message": "The given data was invalid.",
"errors": {
"provider": ["An integration for this provider already exists."]
}
}One Integration Per Provider
Only one integration per provider is allowed. If you need to change credentials, use PATCH /api/v1/integrations/{id} to update the existing record.
Get Integration Details
Returns full details for a single integration. Sensitive credential fields are always masked.
Endpoint: GET /api/v1/integrations/{id}
Authentication: Required (Bearer token)
Example Request:
GET /api/v1/integrations/01hwxyz123abc456def789ghi0Response (200 OK):
{
"success": true,
"data": {
"id": "01hwxyz123abc456def789ghi0",
"provider": "stripe",
"display_name": "Stripe",
"category": "payment",
"status": "active",
"enabled_capabilities": ["initiate_payment", "process_refund", "verify_payment"],
"credentials": {
"publishable_key": "pk_test_placeholder",
"secret_key": null,
"webhook_secret": null
},
"metadata": {
"environment": "production",
"account_label": "Primary Stripe Account"
},
"verified_at": "2026-01-10T08:45:00Z",
"created_at": "2026-01-10T08:30:00Z",
"updated_at": "2026-01-10T08:45:00Z"
},
"meta": {}
}Update Integration
Updates the credentials, enabled capabilities, or metadata for an existing integration. If credentials are changed, the integration is reset to pending_verify and re-verified asynchronously.
Endpoint: PATCH /api/v1/integrations/{id}
Authentication: Required (Bearer token)
Request Body (partial update allowed):
{
"credentials": {
"publishable_key": "pk_test_placeholder_new",
"secret_key": "sk_test_placeholder_new"
},
"enabled_capabilities": ["initiate_payment", "process_refund"],
"metadata": {
"environment": "production",
"account_label": "Primary Stripe Account - rotated Jan 2026"
}
}Response (200 OK):
{
"success": true,
"message": "Integration updated successfully",
"data": {
"id": "01hwxyz123abc456def789ghi0",
"provider": "stripe",
"status": "pending_verify",
"enabled_capabilities": ["initiate_payment", "process_refund"],
"verified_at": null,
"updated_at": "2026-02-01T09:00:00Z"
},
"meta": {}
}Delete Integration
Soft-deletes an integration. Any routing rules that reference this integration will no longer select it. Deleted integrations do not appear in list responses.
Endpoint: DELETE /api/v1/integrations/{id}
Authentication: Required (Bearer token)
Response (200 OK):
{
"success": true,
"message": "Integration deleted successfully"
}Deleting an Active Integration
Deleting an integration that is referenced by active routing rules will leave those rules without a valid target. Review and update your routing rules before deleting a provider integration.
Activate Integration
Re-enables an integration that is currently in inactive status. The integration transitions immediately to active without re-verifying credentials.
Endpoint: POST /api/v1/integrations/{id}/activate
Authentication: Required (Bearer token)
Response (200 OK):
{
"success": true,
"message": "Integration activated successfully",
"data": {
"id": "01hwxyz123abc456def789ghi0",
"status": "active",
"updated_at": "2026-02-15T10:30:00Z"
},
"meta": {}
}Disable Integration
Manually disables an active integration. No new operations will be routed to it until it is re-activated. Existing in-flight delivery attempts continue to completion.
Endpoint: POST /api/v1/integrations/{id}/disable
Authentication: Required (Bearer token)
Response (200 OK):
{
"success": true,
"message": "Integration disabled successfully",
"data": {
"id": "01hwxyz123abc456def789ghi0",
"status": "inactive",
"updated_at": "2026-02-15T11:00:00Z"
},
"meta": {}
}Business Scenarios
Scenario 1: Setting Up Stripe for the First Time
Context: Your tenant is onboarding and needs to accept payments through Stripe.
Workflow:
- List providers to confirm Stripe is available and not yet configured
- Create the integration with credentials from your Stripe dashboard
- Poll for
activestatus before creating routing rules - Create a routing rule targeting the Stripe integration
API Calls:
# 1. Discover providers
GET /api/v1/integrations/providers
# 2. Configure integration
POST /api/v1/integrations
{
"provider": "stripe",
"credentials": {
"publishable_key": "pk_test_placeholder",
"secret_key": "sk_test_placeholder"
},
"enabled_capabilities": ["initiate_payment", "process_refund", "verify_payment"]
}
# 3. Poll for verification
GET /api/v1/integrations/01hwxyz123abc456def789ghi0
# 4. Once active, create routing rule
POST /api/v1/routing-rules
{
"capability": "initiate_payment",
"integration_id": "01hwxyz123abc456def789ghi0",
"is_default": true,
"priority": 100
}Scenario 2: Rotating Credentials
Context: Your security team requires quarterly credential rotation for all payment integrations.
Workflow:
- Generate new credentials in your Stripe dashboard
- Update the integration - the system immediately queues re-verification
- Monitor status until
activeis confirmed - Confirm routing rules are still referencing the same integration ID (they are - IDs do not change)
API Calls:
# 1. Rotate credentials
PATCH /api/v1/integrations/01hwxyz123abc456def789ghi0
{
"credentials": {
"publishable_key": "pk_test_placeholder_new",
"secret_key": "sk_test_placeholder_new"
},
"metadata": {
"rotated_at": "2026-03-01",
"account_label": "Stripe - rotated Q1 2026"
}
}
# 2. Poll until active
GET /api/v1/integrations/01hwxyz123abc456def789ghi0Scenario 3: Switching Communication Providers
Context: You want to move from Plivo to Twilio for SMS delivery.
Workflow:
- Configure Twilio integration
- Wait for Twilio to reach
activestatus - Update routing rules to point to Twilio instead of Plivo
- Disable the Plivo integration to prevent accidental routing
API Calls:
# 1. Configure Twilio
POST /api/v1/integrations
{
"provider": "twilio",
"credentials": {
"account_sid": "account_sid_placeholder",
"auth_token": "auth_token_placeholder",
"from_number": "+15550100000"
},
"enabled_capabilities": ["send_sms", "send_whatsapp"]
}
# 2. Update routing rule to Twilio (after it goes active)
PATCH /api/v1/routing-rules/01hwrule23abc456def789ghi0
{
"integration_id": "01hwxyz456abc789def012ghi3"
}
# 3. Disable Plivo
POST /api/v1/integrations/01hwplivo23abc456def789g0/disableCredential Security
Credentials are encrypted at rest using envelope encryption. The plaintext of any sensitive field - secret keys, auth tokens, webhook secrets - is never stored in the database and is never returned in API responses. Sensitive fields always appear as null in responses regardless of the request context.
Non-sensitive fields such as publishable keys and sender phone numbers are stored in plaintext because they are designed to be public-facing identifiers. These fields remain visible in API responses to help you confirm which account is configured without requiring access to your provider dashboard.
Credentials are never written to application logs. If a verification error occurs, the error description is stored in the integration's metadata field - not the credential values.
Never Share Full Request Bodies
When reporting issues or creating support tickets, do not include raw request bodies that contain credential values. Use the masked API response instead to show the configuration state.
Best Practices
1. Verify Status Before Routing
Always confirm an integration has reached active status before configuring routing rules or triggering operations. Routing evaluation skips non-active integrations, which can result in NoActiveProviderException errors if no other rule matches.
2. Use Metadata for Context
The metadata field is a free-form object attached to each integration. Use it to record when credentials were last rotated, which Stripe account or Twilio sub-account is in use, and what environment (staging vs. production) the credentials belong to. This context is invaluable during incident investigations.
3. Configure a Fallback on Routing Rules
When configuring routing rules, always specify a fallback_integration_id pointing to a secondary provider. If the primary integration becomes unavailable mid-operation, the fallback is used automatically without intervention. See the Routing Rules guide for configuration details.
4. Rotate Credentials Regularly
Establish a credential rotation schedule (quarterly is common) and use the PATCH endpoint to update credentials in place. Integration IDs never change during updates, so routing rules remain valid. Storing the rotation date in metadata makes compliance audits straightforward.
Troubleshooting
Verification Stuck in pending_verify
Symptom: Integration remains in pending_verify for more than a few minutes.
Possible Causes:
- The async verification job is queued behind other work
- The verification job encountered a transient network error and will retry
Resolution:
- Wait up to five minutes for the job to complete
- Check
GET /api/v1/integrations/{id}- ifstatusis stillpending_verify, look atmetadatafor any error details - If
metadatacontains an error, update the credentials to re-queue verification:PATCH /api/v1/integrations/{id}
Credentials Rejected During Verification
Symptom: Integration transitions to error status shortly after configuration.
Possible Causes:
- Credentials were copied incorrectly (extra whitespace, truncation)
- The wrong credential type was used (test key in production or vice versa)
- The provider account does not have the required permissions for all enabled capabilities
Resolution:
- Retrieve the integration:
GET /api/v1/integrations/{id}and checkmetadatafor the error message - Correct the credentials in your provider dashboard
- Update the integration with the corrected credentials:
PATCH /api/v1/integrations/01hwxyz123abc456def789ghi0
{
"credentials": {
"secret_key": "sk_test_corrected_placeholder"
}
}Integration in Error State After Being Active
Symptom: An integration that was previously active has moved to error status.
Possible Causes:
- The provider account was suspended or credentials were revoked externally
- A key expired or was rotated in the provider dashboard without updating the integration
- The provider returned an authentication failure during a live operation
Resolution:
- Log in to your provider dashboard and confirm the account is in good standing
- Generate new credentials if the existing ones were revoked
- Update the integration via
PATCH /api/v1/integrations/{id}to re-trigger verification - Review recent delivery attempts for this integration in the Delivery Tracking section for additional context
Related Documentation
- Routing Rules - Configure which integration handles each capability
- Delivery Tracking - Monitor async delivery attempts and investigate failures
- Integrations Overview - Module architecture and quick start