Pools of provider connections

Create a pool of provider connections, arrange its members, read their live headroom and how the pool served its calls.

A provider pool groups provider connections and decides which of them serves a model call, and what follows when an attempt fails. The operations of this page create a pool, put connections into it, and read its live headroom and how it served its calls. The console shows the same pools on Provider Pools; Provider pools explains the strategies, the failure choices and which calls a pool serves.

Project and organization

A pool belongs to one project or to the whole organization. A pool of the organization has project_id set to null, and every project may send calls through it.

  • scope set to project creates a pool in the project of the key. Without scope and project_id the pool is one of the organization, and a key cannot create it: the answer is 403 with the code project_access_restricted.

  • A key reads the pools of its project and of the organization. It changes only those of its project; a write to a pool of the organization answers the same 403.

  • A pool of another project, or one that does not exist, answers 404 with the code provider_pool_not_found.

A pool lists in connections only the members the key reaches. A connection of another project is left out of the pool, of its headroom and of its analytics.

The settings of a pool

  • provider is the provider whose calls the pool serves by default. It cannot be changed: create another pool.

  • allow_cross_provider lets the pool take connections of other providers. Without it, attaching one answers 422 with the code connection_incompatible. Turning it off later keeps the members already attached.

  • max_attempts — from 1 to 5, 3 when not sent — is how many connections one call may try.

  • on_rate_limit and on_provider_error say what follows a failed attempt. switch_connection is the default of both.

  • status set to disabled stops the pool. It is no longer the default route of its provider, and a model node that names it is refused with provider_not_configured before any provider is called.

The members

Attaching a connection takes its id and, when you want them, its terms.

TermWhat it doesWhen not sent
priorityFrom 1 to 1000. A lower number is tried first1
weightFrom 0 to 100, read by the strategy weighted. A member with 0 is tried only after the others0
enabledfalse keeps the member in the pool and takes it out of usetrue
cost_multiplierA decimal string. The cost of an attempt through this member is multiplied by it"1.0000"
  • The connection must be one the key reaches: another one answers 404 with the code provider_connection_not_found. A connection of the organization may join a pool of the project.

  • A connection that is already a member answers 409 with the code pool_connection_exists, and a deleted connection 422 with connection_incompatible.

  • Changing or detaching a connection that is not a member answers 404 with the code pool_connection_not_found. Detaching keeps the connection and its key.

Deleting a pool

Deleting a pool keeps its connections. A pool that a flow still calls through is not deleted: the answer is 409 with the code pool_in_use. A flow still calls through it when the active version of the flow names it — an archived flow included — or when an execution that has not finished runs on a version that names it.

Headroom and analytics

  • The headroom has a row for each member: its limits, what it has used and what remains, and how many calls it runs at once. model reads the limits of one model. Without it the rows are the limits of the whole connection.

  • The analytics of a pool count its attempts, its operations, how often a call moved to another connection, and how the traffic was spread over the members. The window follows the rules of a report: seven days without from and to, and at most 31 days.

Operations

List provider pools

GET /v1/provider-pools

  • Scope: management:read

Each pool's connections holds the members in the caller's reach, as on GET /v1/provider-pools/{id}.

Parameters

ParameterDescription
limit optional

queryinteger

Page size (default 30).

  • Minimum: 1
  • Maximum: 100
cursor optional

querystring

The meta.next_cursor of the previous page.

provider optional

queryProviderCode

  • One of: openai, anthropic, google
status optional

queryPoolStatus

  • One of: active, disabled
project optional

querystring

current narrows the list to the active project — an API key's own, a person's as switched on POST /api/auth/me/project — plus the organization's rows where the resource has them. A literal, never an id: anything else is 422. Without it the list is everything within the caller's reach.

  • One of: current

Responses

200

One cursor page of pools

application/json
{
  "data": [
    {
      "provider_pool_id": "74438200973594624",
      "organization_id": "74438200973594624",
      "project_id": "74438200973594624",
      "name": "string",
      "provider": "openai",
      "allow_cross_provider": true,
      "strategy": "priority",
      "max_attempts": 1,
      "on_rate_limit": "switch_connection",
      "on_provider_error": "switch_connection",
      "status": "active",
      "connections": [
        {
          "connection_id": "74438200973594624",
          "name": "string",
          "provider": "openai",
          "environment": "production",
          "secret_last_four": "string",
          "status": "active",
          "health_status": "string",
          "priority": 1,
          "weight": 1,
          "enabled": true,
          "cost_multiplier": "string"
        }
      ],
      "created_at": "2026-10-02T09:30:00Z",
      "updated_at": "2026-10-02T09:30:00Z"
    }
  ],
  "meta": {
    "limit": 1,
    "next_cursor": "string"
  }
}

Errors

StatusCodesWhen
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Headers

  • X-Request-Id

The body of every error is the error envelope.

Create a pool

POST /v1/provider-pools

  • Scope: management:write

scope: project is the active project, organization (the default without scope and project_id) is no project and needs a caller that reaches every project (403 project_access_restricted); scope together with project_id is 422. A project_id that is not a project of the caller's organization in its reach is 404 project_not_found and nothing is stored (L3).

Request body

application/json
{
  "name": "string",
  "provider": "openai",
  "strategy": "priority",
  "max_attempts": 1,
  "on_rate_limit": "switch_connection",
  "on_provider_error": "switch_connection",
  "allow_cross_provider": true,
  "project_id": "74438200973594624",
  "scope": "organization"
}

Responses

201

The created pool

application/json
{
  "data": {
    "provider_pool_id": "74438200973594624",
    "organization_id": "74438200973594624",
    "project_id": "74438200973594624",
    "name": "string",
    "provider": "openai",
    "allow_cross_provider": true,
    "strategy": "priority",
    "max_attempts": 1,
    "on_rate_limit": "switch_connection",
    "on_provider_error": "switch_connection",
    "status": "active",
    "connections": [
      {
        "connection_id": "74438200973594624",
        "name": "string",
        "provider": "openai",
        "environment": "production",
        "secret_last_four": "string",
        "status": "active",
        "health_status": "string",
        "priority": 1,
        "weight": 1,
        "enabled": true,
        "cost_multiplier": "string"
      }
    ],
    "created_at": "2026-10-02T09:30:00Z",
    "updated_at": "2026-10-02T09:30:00Z"
  }
}

Errors

StatusCodesWhen
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

404

No such resource for this tenant. Somebody else's resource — and a resource of a project the caller does not reach — answers the same way on purpose: the two must not be distinguishable.

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Headers

  • X-Request-Id

The body of every error is the error envelope.

Read one pool with its members

GET /v1/provider-pools/{id}

  • Scope: management:read

connections holds the members in the caller's reach: a connection of a project out of reach is left out.

Parameters

ParameterDescription
id required

pathId

Snowflake identifier, as a string.

  • Pattern: ^\d+$
  • Example: 74438200973594624

Responses

200

The pool

application/json
{
  "data": {
    "provider_pool_id": "74438200973594624",
    "organization_id": "74438200973594624",
    "project_id": "74438200973594624",
    "name": "string",
    "provider": "openai",
    "allow_cross_provider": true,
    "strategy": "priority",
    "max_attempts": 1,
    "on_rate_limit": "switch_connection",
    "on_provider_error": "switch_connection",
    "status": "active",
    "connections": [
      {
        "connection_id": "74438200973594624",
        "name": "string",
        "provider": "openai",
        "environment": "production",
        "secret_last_four": "string",
        "status": "active",
        "health_status": "string",
        "priority": 1,
        "weight": 1,
        "enabled": true,
        "cost_multiplier": "string"
      }
    ],
    "created_at": "2026-10-02T09:30:00Z",
    "updated_at": "2026-10-02T09:30:00Z"
  }
}

Errors

StatusCodesWhen
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

404

No such resource for this tenant. Somebody else's resource — and a resource of a project the caller does not reach — answers the same way on purpose: the two must not be distinguishable.

Headers

  • X-Request-Id

The body of every error is the error envelope.

Change the strategy or failover behaviour

PATCH /v1/provider-pools/{id}

  • Scope: management:write

provider cannot change — it would orphan every attached connection.

A pool of no project (the organization's) is written only by a caller that reaches every project (403 project_access_restricted).

Parameters

ParameterDescription
id required

pathId

Snowflake identifier, as a string.

  • Pattern: ^\d+$
  • Example: 74438200973594624

Request body

application/json
{
  "name": "string",
  "strategy": "priority",
  "max_attempts": 1,
  "on_rate_limit": "switch_connection",
  "on_provider_error": "switch_connection",
  "status": "active",
  "allow_cross_provider": true
}

Responses

200

The updated pool

application/json
{
  "data": {
    "provider_pool_id": "74438200973594624",
    "organization_id": "74438200973594624",
    "project_id": "74438200973594624",
    "name": "string",
    "provider": "openai",
    "allow_cross_provider": true,
    "strategy": "priority",
    "max_attempts": 1,
    "on_rate_limit": "switch_connection",
    "on_provider_error": "switch_connection",
    "status": "active",
    "connections": [
      {
        "connection_id": "74438200973594624",
        "name": "string",
        "provider": "openai",
        "environment": "production",
        "secret_last_four": "string",
        "status": "active",
        "health_status": "string",
        "priority": 1,
        "weight": 1,
        "enabled": true,
        "cost_multiplier": "string"
      }
    ],
    "created_at": "2026-10-02T09:30:00Z",
    "updated_at": "2026-10-02T09:30:00Z"
  }
}

Errors

StatusCodesWhen
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

404

No such resource for this tenant. Somebody else's resource — and a resource of a project the caller does not reach — answers the same way on purpose: the two must not be distinguishable.

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Headers

  • X-Request-Id

The body of every error is the error envelope.

Delete a pool

DELETE /v1/provider-pools/{id}

  • Scope: management:write

A pool of no project (the organization's) is written only by a caller that reaches every project (403 project_access_restricted).

409 pool_in_use — the pool is named by the live version of a flow (an archived flow's live version counts), or by a version an unfinished execution (running, queued, waiting) is pinned to. A version that was replaced does not hold the pool; a rollback to such a version after the pool is gone is 422 flow_invalid with an unknown_pool issue.

Parameters

ParameterDescription
id required

pathId

Snowflake identifier, as a string.

  • Pattern: ^\d+$
  • Example: 74438200973594624

Responses

204

Deleted

No body

Errors

StatusCodesWhen
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

404

No such resource for this tenant. Somebody else's resource — and a resource of a project the caller does not reach — answers the same way on purpose: the two must not be distinguishable.

409

State conflict: idempotency clash, stale draft, illegal transition; the last owner of an organization (last_owner); the owned-organization limit (organization_limit_reached); an end customer with credit history that cannot be deleted (customer_has_history)

Headers

  • X-Request-Id

The body of every error is the error envelope.

Add a connection to a pool

POST /v1/provider-pools/{id}/connections

  • Scope: management:write

connection_id must be a connection the caller reaches (404 provider_connection_not_found otherwise): another project's credentials never join the caller's pool. Attaching an organization connection to one's own pool is not a write to that connection and is allowed.

A pool of no project (the organization's) is written only by a caller that reaches every project (403 project_access_restricted).

Parameters

ParameterDescription
id required

pathId

Snowflake identifier, as a string.

  • Pattern: ^\d+$
  • Example: 74438200973594624

Request body

application/json
{
  "connection_id": "74438200973594624",
  "priority": 1,
  "weight": 1,
  "enabled": true,
  "cost_multiplier": "100.0000"
}

Responses

201

The pool with the new member

application/json
{
  "data": {
    "provider_pool_id": "74438200973594624",
    "organization_id": "74438200973594624",
    "project_id": "74438200973594624",
    "name": "string",
    "provider": "openai",
    "allow_cross_provider": true,
    "strategy": "priority",
    "max_attempts": 1,
    "on_rate_limit": "switch_connection",
    "on_provider_error": "switch_connection",
    "status": "active",
    "connections": [
      {
        "connection_id": "74438200973594624",
        "name": "string",
        "provider": "openai",
        "environment": "production",
        "secret_last_four": "string",
        "status": "active",
        "health_status": "string",
        "priority": 1,
        "weight": 1,
        "enabled": true,
        "cost_multiplier": "string"
      }
    ],
    "created_at": "2026-10-02T09:30:00Z",
    "updated_at": "2026-10-02T09:30:00Z"
  }
}

Errors

StatusCodesWhen
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

404

No such resource for this tenant. Somebody else's resource — and a resource of a project the caller does not reach — answers the same way on purpose: the two must not be distinguishable.

409

State conflict: idempotency clash, stale draft, illegal transition; the last owner of an organization (last_owner); the owned-organization limit (organization_limit_reached); an end customer with credit history that cannot be deleted (customer_has_history)

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Headers

  • X-Request-Id

The body of every error is the error envelope.

Change a member's priority, weight or cost multiplier

PATCH /v1/provider-pools/{id}/connections/{connectionId}

  • Scope: management:write

A pool of no project (the organization's) is written only by a caller that reaches every project (403 project_access_restricted).

Parameters

ParameterDescription
id required

pathId

Snowflake identifier, as a string.

  • Pattern: ^\d+$
  • Example: 74438200973594624
connectionId required

pathId

Provider connection id.

  • Pattern: ^\d+$
  • Example: 74438200973594624

Request body

application/json
{
  "priority": 1,
  "weight": 1,
  "enabled": true,
  "cost_multiplier": "100.0000"
}

Responses

200

The pool with the updated member

application/json
{
  "data": {
    "provider_pool_id": "74438200973594624",
    "organization_id": "74438200973594624",
    "project_id": "74438200973594624",
    "name": "string",
    "provider": "openai",
    "allow_cross_provider": true,
    "strategy": "priority",
    "max_attempts": 1,
    "on_rate_limit": "switch_connection",
    "on_provider_error": "switch_connection",
    "status": "active",
    "connections": [
      {
        "connection_id": "74438200973594624",
        "name": "string",
        "provider": "openai",
        "environment": "production",
        "secret_last_four": "string",
        "status": "active",
        "health_status": "string",
        "priority": 1,
        "weight": 1,
        "enabled": true,
        "cost_multiplier": "string"
      }
    ],
    "created_at": "2026-10-02T09:30:00Z",
    "updated_at": "2026-10-02T09:30:00Z"
  }
}

Errors

StatusCodesWhen
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

404

No such resource for this tenant. Somebody else's resource — and a resource of a project the caller does not reach — answers the same way on purpose: the two must not be distinguishable.

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Headers

  • X-Request-Id

The body of every error is the error envelope.

Remove a connection from a pool

DELETE /v1/provider-pools/{id}/connections/{connectionId}

  • Scope: management:write

A pool of no project (the organization's) is written only by a caller that reaches every project (403 project_access_restricted).

Parameters

ParameterDescription
id required

pathId

Snowflake identifier, as a string.

  • Pattern: ^\d+$
  • Example: 74438200973594624
connectionId required

pathId

Provider connection id.

  • Pattern: ^\d+$
  • Example: 74438200973594624

Responses

204

Detached

No body

Errors

StatusCodesWhen
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

404

No such resource for this tenant. Somebody else's resource — and a resource of a project the caller does not reach — answers the same way on purpose: the two must not be distinguishable.

Headers

  • X-Request-Id

The body of every error is the error envelope.

Live headroom of every member

GET /v1/provider-pools/{id}/capacity

  • Scope: management:read

Omitting model reads the connection-wide default limits. One row per member in the caller's reach.

Parameters

ParameterDescription
id required

pathId

Snowflake identifier, as a string.

  • Pattern: ^\d+$
  • Example: 74438200973594624
model optional

querystring

  • Maximum length: 64

Responses

200

One row per member connection

application/json
{
  "data": [
    {
      "connection_id": "74438200973594624",
      "model": "gpt-4o-mini",
      "limits": {
        "rpm": 1,
        "tpm": 1,
        "input_tpm": 1,
        "output_tpm": 1,
        "max_concurrency": 1,
        "daily_quota": 1
      },
      "used": {
        "requests": 1,
        "tokens": 1
      },
      "remaining": {
        "requests": 1,
        "tokens": 1
      },
      "active_concurrency": 1,
      "reset_at": "2026-10-02T09:30:00Z"
    }
  ]
}

Errors

StatusCodesWhen
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

404

No such resource for this tenant. Somebody else's resource — and a resource of a project the caller does not reach — answers the same way on purpose: the two must not be distinguishable.

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Headers

  • X-Request-Id

The body of every error is the error envelope.

Failovers, availability and traffic split of a pool

GET /v1/provider-pools/{id}/analytics

  • Scope: read

traffic_distribution names the connections in the caller's reach only; the pool's totals are the pool's own.

Parameters

ParameterDescription
id required

pathId

Snowflake identifier, as a string.

  • Pattern: ^\d+$
  • Example: 74438200973594624
from optional

querystring

Start of the window an analytics answer covers — a date the server can parse, ISO-8601 recommended (a value without an offset is read as UTC). Unlike the lists, each end is optional on its own and the window is never refused, only fitted (AnalyticsWindowResolver):

  • Format: date-time
to optional

querystring

End of the window an analytics answer covers; now when absent. See from (WindowFrom) for how the window is fitted rather than refused.

  • Format: date-time

Responses

200

Pool analytics for the window

application/json
{
  "data": {
    "pool_id": "74438200973594624",
    "window": {
      "from": "2026-10-02T09:30:00Z",
      "to": "2026-10-02T09:30:00Z"
    },
    "total_attempts": 1,
    "operations": 1,
    "failover_count": 1,
    "requests_saved_from_rejection": 1,
    "total_cost": "0.02700000",
    "availability": "string",
    "traffic_distribution": [
      {
        "connection_id": "74438200973594624",
        "attempts": 1,
        "succeeded": 1,
        "share": "string",
        "cost": "0.02700000"
      }
    ]
  }
}

Errors

StatusCodesWhen
401

No credential, or one that is not valid

403

Authenticated, but not allowed: scope (insufficient_scope), policy or tenant (not_a_member); a blocked end customer (customer_blocked); an act only a signed-in person may take (session_required); the role rule on members and invitations (member_forbidden, invite_forbidden); a write to the organization's own rows, or a read of the audit journal, by a caller that does not reach every project (project_access_restricted)

404

No such resource for this tenant. Somebody else's resource — and a resource of a project the caller does not reach — answers the same way on purpose: the two must not be distinguishable.

422

Validation failure or a semantically impossible request. Field-level validation from the framework answers {"message", "errors"}; domain refusals answer the standard error envelope. An Idempotency-Key longer than 190 characters is invalid_request in that envelope.

Headers

  • X-Request-Id

The body of every error is the error envelope.

Examples

List the pools

The list holds the pools the key reaches: those of its project and of the organization.

Terminal
curl https://api.slen.ai/api/v1/provider-pools \
  -H "Authorization: Bearer $SLEN_API_KEY"
200 OK
{
  "data": [
    {
      "provider_pool_id": "74438955400675328",
      "organization_id": "74438200973594112",
      "project_id": "74438200973594624",
      "name": "OpenAI",
      "provider": "openai",
      "allow_cross_provider": false,
      "strategy": "priority",
      "max_attempts": 3,
      "on_rate_limit": "switch_connection",
      "on_provider_error": "switch_connection",
      "status": "active",
      "connections": [
        {
          "connection_id": "74438912450035712",
          "name": "OpenAI production",
          "provider": "openai",
          "environment": "production",
          "secret_last_four": "c81d",
          "status": "active",
          "health_status": "healthy",
          "priority": 1,
          "weight": 0,
          "enabled": true,
          "cost_multiplier": "1.0000"
        }
      ],
      "created_at": "2026-10-02T08:14:02+00:00",
      "updated_at": "2026-10-02T08:14:02+00:00"
    }
  ],
  "meta": {
    "limit": 30,
    "next_cursor": null
  }
}

Create a pool

A pool of the project, ordered by priority. The pool has no members yet.

Terminal
curl https://api.slen.ai/api/v1/provider-pools \
  -H "Authorization: Bearer $SLEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "scope": "project",
    "name": "OpenAI failover",
    "provider": "openai",
    "strategy": "priority",
    "max_attempts": 3
  }'
201 Created
{
  "data": {
    "provider_pool_id": "74443250117779456",
    "organization_id": "74438200973594112",
    "project_id": "74438200973594624",
    "name": "OpenAI failover",
    "provider": "openai",
    "allow_cross_provider": false,
    "strategy": "priority",
    "max_attempts": 3,
    "on_rate_limit": "switch_connection",
    "on_provider_error": "switch_connection",
    "status": "active",
    "connections": [],
    "created_at": "2026-10-02T10:02:17+00:00",
    "updated_at": "2026-10-02T10:02:17+00:00"
  }
}

Read a pool

The answer is the pool, in the shape the answer above has, with its members.

Terminal
curl https://api.slen.ai/api/v1/provider-pools/74438955400675328 \
  -H "Authorization: Bearer $SLEN_API_KEY"
200 OK
{
  "data": {
    "provider_pool_id": "74438955400675328",
    "organization_id": "74438200973594112",
    "project_id": "74438200973594624",
    "name": "OpenAI",
    "provider": "openai",
    "allow_cross_provider": false,
    "strategy": "priority",
    "max_attempts": 3,
    "on_rate_limit": "switch_connection",
    "on_provider_error": "switch_connection",
    "status": "active",
    "connections": [
      {
        "connection_id": "74438912450035712",
        "name": "OpenAI production",
        "provider": "openai",
        "environment": "production",
        "secret_last_four": "c81d",
        "status": "active",
        "health_status": "healthy",
        "priority": 1,
        "weight": 0,
        "enabled": true,
        "cost_multiplier": "1.0000"
      }
    ],
    "created_at": "2026-10-02T08:14:02+00:00",
    "updated_at": "2026-10-02T08:14:02+00:00"
  }
}

Change the settings

The pool moves to the strategy weighted. Its provider and its members stay.

Terminal
curl -X PATCH https://api.slen.ai/api/v1/provider-pools/74438955400675328 \
  -H "Authorization: Bearer $SLEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "strategy": "weighted"
  }'
200 OK
{
  "data": {
    "provider_pool_id": "74438955400675328",
    "organization_id": "74438200973594112",
    "project_id": "74438200973594624",
    "name": "OpenAI",
    "provider": "openai",
    "allow_cross_provider": false,
    "strategy": "weighted",
    "max_attempts": 3,
    "on_rate_limit": "switch_connection",
    "on_provider_error": "switch_connection",
    "status": "active",
    "connections": [
      {
        "connection_id": "74438912450035712",
        "name": "OpenAI production",
        "provider": "openai",
        "environment": "production",
        "secret_last_four": "c81d",
        "status": "active",
        "health_status": "healthy",
        "priority": 1,
        "weight": 0,
        "enabled": true,
        "cost_multiplier": "1.0000"
      }
    ],
    "created_at": "2026-10-02T08:14:02+00:00",
    "updated_at": "2026-10-02T10:05:40+00:00"
  }
}

Delete a pool

The answer has no body.

Terminal
curl -X DELETE https://api.slen.ai/api/v1/provider-pools/74443250117779456 \
  -H "Authorization: Bearer $SLEN_API_KEY"

204 No Content

Attach a connection

The connection becomes the first member to try. The answer is the pool with its new member.

Terminal
curl https://api.slen.ai/api/v1/provider-pools/74443250117779456/connections \
  -H "Authorization: Bearer $SLEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "connection_id": "74438912450035712",
    "priority": 1
  }'
201 Created
{
  "data": {
    "provider_pool_id": "74443250117779456",
    "organization_id": "74438200973594112",
    "project_id": "74438200973594624",
    "name": "OpenAI failover",
    "provider": "openai",
    "allow_cross_provider": false,
    "strategy": "priority",
    "max_attempts": 3,
    "on_rate_limit": "switch_connection",
    "on_provider_error": "switch_connection",
    "status": "active",
    "connections": [
      {
        "connection_id": "74438912450035712",
        "name": "OpenAI production",
        "provider": "openai",
        "environment": "production",
        "secret_last_four": "c81d",
        "status": "active",
        "health_status": "healthy",
        "priority": 1,
        "weight": 0,
        "enabled": true,
        "cost_multiplier": "1.0000"
      }
    ],
    "created_at": "2026-10-02T10:02:17+00:00",
    "updated_at": "2026-10-02T10:03:05+00:00"
  }
}

Change a member

The member gets a weight for the strategy weighted.

Terminal
curl -X PATCH https://api.slen.ai/api/v1/provider-pools/74438955400675328/connections/74438912450035712 \
  -H "Authorization: Bearer $SLEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "weight": 70
  }'
200 OK
{
  "data": {
    "provider_pool_id": "74438955400675328",
    "organization_id": "74438200973594112",
    "project_id": "74438200973594624",
    "name": "OpenAI",
    "provider": "openai",
    "allow_cross_provider": false,
    "strategy": "weighted",
    "max_attempts": 3,
    "on_rate_limit": "switch_connection",
    "on_provider_error": "switch_connection",
    "status": "active",
    "connections": [
      {
        "connection_id": "74438912450035712",
        "name": "OpenAI production",
        "provider": "openai",
        "environment": "production",
        "secret_last_four": "c81d",
        "status": "active",
        "health_status": "healthy",
        "priority": 1,
        "weight": 70,
        "enabled": true,
        "cost_multiplier": "1.0000"
      }
    ],
    "created_at": "2026-10-02T08:14:02+00:00",
    "updated_at": "2026-10-02T10:05:40+00:00"
  }
}

Detach a connection

The answer has no body. The connection stays as it was.

Terminal
curl -X DELETE https://api.slen.ai/api/v1/provider-pools/74443250117779456/connections/74438912450035712 \
  -H "Authorization: Bearer $SLEN_API_KEY"

204 No Content

Read the headroom

The member has used 112 of the 500 requests a minute its limits allow.

Terminal
curl "https://api.slen.ai/api/v1/provider-pools/74438955400675328/capacity?model=gpt-4o-mini" \
  -H "Authorization: Bearer $SLEN_API_KEY"
200 OK
{
  "data": [
    {
      "connection_id": "74438912450035712",
      "model": "gpt-4o-mini",
      "limits": {
        "rpm": 500,
        "tpm": 200000,
        "input_tpm": null,
        "output_tpm": null,
        "max_concurrency": 20,
        "daily_quota": null
      },
      "used": {
        "requests": 112,
        "tokens": 41250
      },
      "remaining": {
        "requests": 388,
        "tokens": 158750
      },
      "active_concurrency": 3,
      "reset_at": "2026-10-02T10:06:00+00:00"
    }
  ]
}

Read how the pool served

The window is the last seven days.

Terminal
curl https://api.slen.ai/api/v1/provider-pools/74438955400675328/analytics \
  -H "Authorization: Bearer $SLEN_API_KEY"

Where to go next

Built from openapi b070e1f, sdk contract 5cc7055, php ae4a53b, node 84bc62d