Skip to main content

Providers

A provider is a registered external API that modules call through the Integration Hub. Each tenant manages their own set of providers — a provider registered by one tenant is invisible to all others (RLS enforced by tenant_id).


Provider Model

FieldTypeDescription
idUUIDUnique identifier
namestringHuman-readable name (e.g. "Stripe Production", "Twilio SMS")
typeenumProvider category — see types below
baseUrlstringBase URL of the external API (e.g. https://api.stripe.com)
authTypeenumAuthentication method — see auth types below
credentialsencrypted JSONAPI keys, tokens, secrets. AES-256-GCM encrypted at rest.
configJSONPer-provider config: timeout_ms, retries, custom headers
tenantIdUUIDOwner tenant
statusenumactive, degraded, down, disabled
circuitBreakerStateenumclosed, half_open, open
createdAtISO 8601Creation timestamp
updatedAtISO 8601Last update timestamp

Provider Types

TypeUse cases
paymentStripe, PayPal, Adyen, CloudPayments
smsTwilio, AWS SNS, MessageBird
emailSendGrid, Mailgun, Amazon SES
analyticsAmplitude, Mixpanel, Google Analytics
advertisingFacebook Ads, Google Ads, TikTok
customAny other external HTTP API

Auth Types

Auth typeHow credentials are injectedCredentials structure
api_keyX-API-Key: {key} header{ "apiKey": "sk_live_..." }
bearerAuthorization: Bearer {token}{ "token": "eyJ..." }
basicAuthorization: Basic {base64(user:pass)}{ "username": "...", "password": "..." }
oauth2Access token obtained via client credentials flow, auto-refreshed{ "clientId": "...", "clientSecret": "...", "tokenUrl": "..." }
hmacRequest body signed with secret (e.g. Stripe webhook-style outgoing){ "secret": "whsec_...", "algorithm": "sha256" }

Auth headers are injected by the Hub at call time. Credentials are never returned to the caller — the Hub reads the encrypted value from PostgreSQL, decrypts it in memory using the Vault-managed AES-256-GCM key, and injects it into the outgoing HTTP request.


Credential Encryption

Register provider (POST /api/v1/integrations/providers):
credentials field (plaintext in request body, TLS protected)
↓ Hub receives
Hub fetches encryption key from HashiCorp Vault
Hub encrypts: AES-256-GCM(credentials JSON, key)
Hub stores encrypted bytes in PostgreSQL credentials column
Hub returns provider record (credentials field OMITTED from response)

Call provider (POST /api/v1/integrations/call):
Hub reads encrypted credentials from PostgreSQL
Hub fetches key from Vault
Hub decrypts in-memory (AES-256-GCM)
Hub injects into outgoing request
Plaintext credentials never leave the Hub process

Credentials are never returned in any API response — not in GET, not in PATCH, not in health checks. The credentials field is always omitted or shown as "[encrypted]" in responses.


Provider Status

StatusMeaning
activeProvider is healthy, circuit breaker CLOSED
degradedProvider is responding but latency is above threshold (response time > 2s)
downCircuit breaker is OPEN — provider is not reachable
disabledManually disabled by the tenant admin — no calls made

Status is computed by the Hub and stored in Valkey. It is updated:

  • After every successful/failed call
  • By the background health check worker (every 60 seconds)
  • Immediately when the circuit breaker changes state

Register a Provider

POST https://api.septemcore.com/v1/integrations/providers
Authorization: Bearer <access_token>
Content-Type: application/json

{
"name": "Stripe Production",
"type": "payment",
"baseUrl": "https://api.stripe.com",
"authType": "bearer",
"credentials": {
"token": "sk_live_abc123def456"
},
"config": {
"timeout_ms": 10000,
"retries": 3
}
}

Response 201 Created:

{
"id": "01j9pint0000000000000000",
"name": "Stripe Production",
"type": "payment",
"baseUrl": "https://api.stripe.com",
"authType": "bearer",
"credentials": "[encrypted]",
"config": { "timeout_ms": 10000, "retries": 3 },
"tenantId": "01j9ten0000000000000000",
"status": "active",
"circuitBreakerState": "closed",
"createdAt": "2026-04-22T01:50:00Z",
"updatedAt": "2026-04-22T01:50:00Z"
}

Get Provider List

GET https://api.septemcore.com/v1/integrations/providers?page=1&limit=20
Authorization: Bearer <access_token>
{
"items": [
{
"id": "01j9pint0000000000000000",
"name": "Stripe Production",
"type": "payment",
"status": "active",
"circuitBreakerState": "closed",
"updatedAt": "2026-04-22T01:50:00Z"
}
],
"total": 1,
"page": 1,
"limit": 20
}

Update Provider

PATCH https://api.septemcore.com/v1/integrations/providers/01j9pint0000000000000000
Authorization: Bearer <access_token>
Content-Type: application/json

{
"credentials": {
"token": "sk_live_newkey789"
},
"config": {
"timeout_ms": 15000
}
}

Response 200 OK — same shape as 201, credentials field always shown as "[encrypted]".


Provider Health Check

GET https://api.septemcore.com/v1/integrations/providers/01j9pint0000000000000000/health
Authorization: Bearer <access_token>
{
"providerId": "01j9pint0000000000000000",
"name": "Stripe Production",
"status": "active",
"circuitBreakerState": "closed",
"latencyMs": 142,
"lastCheckedAt": "2026-04-22T01:49:00Z",
"lastErrorAt": null,
"lastError": null
}

When the circuit breaker is OPEN:

{
"providerId": "01j9pint0000000000000000",
"name": "Stripe Production",
"status": "down",
"circuitBreakerState": "open",
"latencyMs": null,
"lastCheckedAt": "2026-04-22T01:49:00Z",
"lastErrorAt": "2026-04-22T01:48:55Z",
"lastError": "connection timeout after 10000ms"
}

Delete Provider

DELETE https://api.septemcore.com/v1/integrations/providers/01j9pint0000000000000000
Authorization: Bearer <access_token>

Response 204 No Content.

Deletion is a soft delete — the provider record is marked as deleted, credentials are purged from the database, and any outstanding DLQ entries for this provider are also soft-deleted.


Error Reference

ScenarioHTTPProblem type
Provider not found404not-found
Duplicate name for tenant409conflict
Invalid credentials format400validation-error
Circuit breaker OPEN503service-unavailable
Outgoing rate limit exceeded429rate-limit-exceeded
External API timeout504gateway-timeout