Sign in to fill these examples with your own keys. Sign in Start free trial

IP pools

Named sets of dedicated IPs that mail picks with X-Capsule-Pool.

An IP pool is a named set of your dedicated IPs that mail opts into with the X-Capsule-Pool header. Every cluster keeps its default pool: the sending IPs on the cluster. Mail with no header sends from the default pool. A pool has a classification, transactional or bulk, that can't change later. It holds dedicated IPs your team owns of that class, each with a weight from 1 to 100 (default 100). Weights are relative and don't need to add up to 100. Attach a pool to any of your live shared clusters of the same class, then send with X-Capsule-Pool: . An IP sends from a cluster's default pool or from IP pools, never both, so unpinned mail never uses a pool IP. An IP can sit in several of your pools. Adding a reserved dedicated IP to a pool starts its 14-day warm-up. While every IP in a pool is still warming, a pool with warmup_overflow on (the default) sends the mail its IPs can't take yet from the cluster's default pool. With warmup_overflow off, that mail waits for the warming IPs. Pool mail counts toward the cluster's hourly and daily caps. Writes return 403 {error: team_suspended} while the account is suspended, except delete and detach.

GET /api/v1/teams/:obfuscated_team_id/ip_pools

List the team's IP pools by name, with their IPs, weights, and attached clusters.

  • classification: Optional. transactional or bulk.
request.sh
1curl -sS -X GET \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 https://app.postshiba.com/api/v1/teams/KjkAJW/ip_pools
response.json
1[ 2 { 3 "id": "PoOlIp", 4 "name": "site_123", 5 "classification": "bulk", 6 "warmup_overflow": true, 7 "ips": [ 8 { 9 "id": "IpQwEr", 10 "address": "198.51.100.10", 11 "status": "warming", 12 "warmup_ends_at": "2026-10-23T12:00:00Z", 13 "weight": 100 14 } 15 ], 16 "cluster_ids": [ 17 "NmQpXr" 18 ], 19 "created_at": "2026-10-09T12:00:00Z" 20 } 21]

POST /api/v1/teams/:obfuscated_team_id/ip_pools

Create an empty pool. name is lowercased and trimmed. It must be 1 to 63 characters of a-z, 0-9, _ and -, start with a letter or digit, and be unique in the team. default is reserved. Returns 422 {error: name_taken, errors} when the team already has a pool with that name, and 422 {error: invalid, errors} for any other invalid field.

  • name: Pool name. The value you send in X-Capsule-Pool.
  • classification: transactional or bulk. Can't change later.
  • warmup_overflow: Optional, default true. While every IP in the pool is warming, send what they can't take yet from the cluster's default pool.
request.sh
1curl -sS -X POST \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 -H 'Content-Type: application/json' \ 4 -d '{"name":"site_123","classification":"bulk","warmup_overflow":true}' \ 5 https://app.postshiba.com/api/v1/teams/KjkAJW/ip_pools
response.json
1{ 2 "id": "PoOlIp", 3 "name": "site_123", 4 "classification": "bulk", 5 "warmup_overflow": true, 6 "ips": [], 7 "cluster_ids": [], 8 "created_at": "2026-10-09T12:00:00Z" 9}

GET /api/v1/ip_pools/:id

Get one pool.

  • id: Public IP pool id
request.sh
1curl -sS -X GET \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 https://app.postshiba.com/api/v1/ip_pools/:id
response.json
1{ 2 "id": "PoOlIp", 3 "name": "site_123", 4 "classification": "bulk", 5 "warmup_overflow": true, 6 "ips": [ 7 { 8 "id": "IpQwEr", 9 "address": "198.51.100.10", 10 "status": "warming", 11 "warmup_ends_at": "2026-10-23T12:00:00Z", 12 "weight": 100 13 } 14 ], 15 "cluster_ids": [ 16 "NmQpXr" 17 ], 18 "created_at": "2026-10-09T12:00:00Z" 19}

PATCH /api/v1/ip_pools/:id

Rename a pool or change warmup_overflow. classification is ignored. Mail already queued under the old name keeps its pool. Returns 422 name_taken or invalid like create.

  • id: Public IP pool id
request.sh
1curl -sS -X PATCH \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 -H 'Content-Type: application/json' \ 4 -d '{"name":"site_123_bulk","warmup_overflow":false}' \ 5 https://app.postshiba.com/api/v1/ip_pools/:id
response.json
1{ 2 "id": "PoOlIp", 3 "name": "site_123_bulk", 4 "classification": "bulk", 5 "warmup_overflow": false, 6 "ips": [ 7 { 8 "id": "IpQwEr", 9 "address": "198.51.100.10", 10 "status": "warming", 11 "warmup_ends_at": "2026-10-23T12:00:00Z", 12 "weight": 100 13 } 14 ], 15 "cluster_ids": [ 16 "NmQpXr" 17 ], 18 "created_at": "2026-10-09T12:00:00Z" 19}

DELETE /api/v1/ip_pools/:id

Delete a pool. Its IPs stay with your team. Returns 422 pool_attached while it is attached to a live cluster. Detach it first.

  • id: Public IP pool id
request.sh
1curl -sS -X DELETE \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 https://app.postshiba.com/api/v1/ip_pools/:id
response.json
1{ 2 "id": "PoOlIp", 3 "name": "site_123", 4 "classification": "bulk", 5 "warmup_overflow": true, 6 "ips": [ 7 { 8 "id": "IpQwEr", 9 "address": "198.51.100.10", 10 "status": "warming", 11 "warmup_ends_at": "2026-10-23T12:00:00Z", 12 "weight": 100 13 } 14 ], 15 "cluster_ids": [], 16 "created_at": "2026-10-09T12:00:00Z" 17}

POST /api/v1/ip_pools/:id/add_ip

Add a dedicated IP your team owns, or change its weight if it is already in the pool. A reserved IP starts its 14-day warm-up. Returns 404 when the IP isn't a dedicated IP your team owns, and 422 class_mismatch, in_default_pool when the IP sends from a cluster's default pool (unassign it first), weight when weight isn't a whole number from 1 to 100, or ip_unusable when the IP is released or quarantined.

  • id: Public IP pool id
  • ip_address_id: Public id of a dedicated IP your team owns
  • weight: Optional. 1 to 100. Defaults to 100 for a new IP and keeps the current weight when re-adding.
request.sh
1curl -sS -X POST \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 -H 'Content-Type: application/json' \ 4 -d '{"ip_address_id":"IpQwEr","weight":100}' \ 5 https://app.postshiba.com/api/v1/ip_pools/:id/add_ip
response.json
1{ 2 "id": "PoOlIp", 3 "name": "site_123", 4 "classification": "bulk", 5 "warmup_overflow": true, 6 "ips": [ 7 { 8 "id": "IpQwEr", 9 "address": "198.51.100.10", 10 "status": "warming", 11 "warmup_ends_at": "2026-10-23T12:00:00Z", 12 "weight": 100 13 } 14 ], 15 "cluster_ids": [ 16 "NmQpXr" 17 ], 18 "created_at": "2026-10-09T12:00:00Z" 19}

POST /api/v1/ip_pools/:id/remove_ip

Remove an IP from the pool. The IP stays with your team. Queued mail pinned to it goes out on the rest of the pool. Returns 404 when the IP isn't in the pool, and 422 last_ip when the pool is attached to a live cluster and this is its last live IP.

  • id: Public IP pool id
  • ip_address_id: Public IP id
request.sh
1curl -sS -X POST \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 -H 'Content-Type: application/json' \ 4 -d '{"ip_address_id":"IpQwEr"}' \ 5 https://app.postshiba.com/api/v1/ip_pools/:id/remove_ip
response.json
1{ 2 "id": "PoOlIp", 3 "name": "site_123", 4 "classification": "bulk", 5 "warmup_overflow": true, 6 "ips": [], 7 "cluster_ids": [ 8 "NmQpXr" 9 ], 10 "created_at": "2026-10-09T12:00:00Z" 11}

POST /api/v1/ip_pools/:id/attach

Attach the pool to one of your live clusters so its mail can use X-Capsule-Pool. Attaching again is a no-op. Returns 404 for another team's cluster or a deprovisioned one, and 422 class_mismatch when the classes differ, dedicated_cluster for a dedicated-node cluster, or empty_pool when the pool has no live IPs.

  • id: Public IP pool id
  • cluster_id: Public cluster id
request.sh
1curl -sS -X POST \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 -H 'Content-Type: application/json' \ 4 -d '{"cluster_id":"NmQpXr"}' \ 5 https://app.postshiba.com/api/v1/ip_pools/:id/attach
response.json
1{ 2 "id": "PoOlIp", 3 "name": "site_123", 4 "classification": "bulk", 5 "warmup_overflow": true, 6 "ips": [ 7 { 8 "id": "IpQwEr", 9 "address": "198.51.100.10", 10 "status": "warming", 11 "warmup_ends_at": "2026-10-23T12:00:00Z", 12 "weight": 100 13 } 14 ], 15 "cluster_ids": [ 16 "NmQpXr" 17 ], 18 "created_at": "2026-10-09T12:00:00Z" 19}

POST /api/v1/ip_pools/:id/detach

Detach the pool from a cluster. New mail with this X-Capsule-Pool on that cluster is rejected with 550. Mail already queued for the pool stays queued and is retried. It never goes out on the default pool. Returns 404 for another team's cluster.

  • id: Public IP pool id
  • cluster_id: Public cluster id
request.sh
1curl -sS -X POST \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 -H 'Content-Type: application/json' \ 4 -d '{"cluster_id":"NmQpXr"}' \ 5 https://app.postshiba.com/api/v1/ip_pools/:id/detach
response.json
1{ 2 "id": "PoOlIp", 3 "name": "site_123", 4 "classification": "bulk", 5 "warmup_overflow": true, 6 "ips": [ 7 { 8 "id": "IpQwEr", 9 "address": "198.51.100.10", 10 "status": "warming", 11 "warmup_ends_at": "2026-10-23T12:00:00Z", 12 "weight": 100 13 } 14 ], 15 "cluster_ids": [], 16 "created_at": "2026-10-09T12:00:00Z" 17}