# VPC networks

Private networks, their subnets, and the firewall rules on each subnet.

Source: https://docs.pantechdynamics.com/api/networks

A VPC is a private network of your own. Create one, add subnets inside its CIDR, then create instances with a `subnet_id`. Each subnet has numbered firewall rules, evaluated lowest number first; the first match decides. To reach a VPC instance from the internet, give it a [public IP](https://docs.pantechdynamics.com/api/public-ips).

Endpoints:

- `GET /public/v1/networks`: List VPC networks
- `POST /public/v1/networks`: Create a VPC network
- `GET /public/v1/networks/quote`: Price a VPC network
- `GET /public/v1/networks/{network_id}`: Get a VPC network
- `DELETE /public/v1/networks/{network_id}`: Delete a VPC network
- `GET /public/v1/networks/{network_id}/subnets`: List subnets
- `POST /public/v1/networks/{network_id}/subnets`: Create a subnet
- `GET /public/v1/subnets/{subnet_id}`: Get a subnet
- `DELETE /public/v1/subnets/{subnet_id}`: Delete a subnet
- `GET /public/v1/subnets/{subnet_id}/firewall-rules`: List a subnet's firewall rules
- `POST /public/v1/subnets/{subnet_id}/firewall-rules`: Add a firewall rule
- `GET /public/v1/subnets/{subnet_id}/firewall-rules/{rule_id}`: Get a firewall rule
- `DELETE /public/v1/firewall-rules/{rule_id}`: Delete a firewall rule

## The network object

A VPC: a private network of your own.

- `id` (string, required): e.g. `net_...`.
- `name` (string, required): Its name, unique among your VPC networks.
- `cidr` (string, required): e.g. `10.0.0.0/16`.
- `region` (string or null): e.g. `af-abj`.
- `zone` (string or null): e.g. `af-abj-2`.
- `instance_count` (integer or null): Instances in this VPC; null when it could not be counted.
- `desired_state` (string, required): What you asked for: `present`, or `deleted` once you deleted it. One of `present`, `deleted`.
- `observed_state` (string, required): What the platform last observed: `pending` and `provisioning` while it is being created, `active` once ready, `deleting`/`deleted` on the way out, `failed` if it could not be made, `unknown` when it could not be checked. One of `pending`, `provisioning`, `active`, `deleting`, `deleted`, `failed`, `unknown`.
- `created_at` (string or null): When it was created (RFC 3339, UTC).
- `updated_at` (string or null): When it last changed (RFC 3339, UTC).
## The subnet object



- `id` (string, required): e.g. `snet_...`.
- `network_id` (string, required)
- `name` (string, required): Its name.
- `cidr` (string, required): Inside the VPC's CIDR.
- `region` (string or null): e.g. `af-abj`.
- `zone` (string or null): e.g. `af-abj-2`.
- `instance_count` (integer or null): Instances in this subnet; null when they could not be counted.
- `desired_state` (string, required): What you asked for: `present`, or `deleted` once you deleted it. One of `present`, `deleted`.
- `observed_state` (string, required): What the platform last observed: `pending` and `provisioning` while it is being created, `active` once ready, `deleting`/`deleted` on the way out, `failed` if it could not be made, `unknown` when it could not be checked. One of `pending`, `provisioning`, `active`, `deleting`, `deleted`, `failed`, `unknown`.
- `created_at` (string or null): When it was created (RFC 3339, UTC).
- `updated_at` (string or null): When it last changed (RFC 3339, UTC).
## The firewall rule object



- `id` (string, required): e.g. `aclr_...`.
- `subnet_id` (string, required): The subnet the rule applies to, as a whole.
- `number` (integer, required): Evaluation order, 100-9999; lowest first. From 100 to 9999.
- `direction` (string, required): `ingress` (into the subnet) or `egress` (out of it). One of `ingress`, `egress`.
- `protocol` (string, required): `tcp`, `udp`, `icmp` or `all`. One of `tcp`, `udp`, `icmp`, `all`.
- `port_start` (integer or null): First port, for `tcp`/`udp`; null otherwise.
- `port_end` (integer or null): Last port, for `tcp`/`udp`; null otherwise.
- `icmp_type` (integer or null): ICMP type, for `icmp`; null for every type.
- `icmp_code` (integer or null): ICMP code, for `icmp`; null for every code.
- `cidr` (string, required): Source (ingress) or destination (egress), e.g. `0.0.0.0/0`.
- `action` (string, required): `allow` or `deny`. One of `allow`, `deny`.
- `desired_state` (string, required): What you asked for: `present`, or `deleted` once you deleted it. One of `present`, `deleted`.
- `observed_state` (string, required): What the platform last observed: `pending` and `provisioning` while it is being created, `active` once ready, `deleting`/`deleted` on the way out, `failed` if it could not be made, `unknown` when it could not be checked. One of `pending`, `provisioning`, `active`, `deleting`, `deleted`, `failed`, `unknown`.
- `created_at` (string or null): When it was created (RFC 3339, UTC).
- `updated_at` (string or null): When it last changed (RFC 3339, UTC).
## List VPC networks

```http
GET /public/v1/networks
```

Your VPC networks, newest first. Filter by name with `q`, or by state.

Scope: `read`.

Query parameters:

- `limit` (integer): Items per page, 1 to 100. Defaults to 50. From 1 to 100. Defaults to `50`.
- `cursor` (string): The previous page's `next_cursor`, to get the next page. Leave out for the first page; keep the other parameters the same.
- `q` (string): Only items whose name contains this text (case-insensitive), at most 255 characters. At most 255 characters.
- `desired_state` (string): Only items with this `desired_state`: `present` or `deleted`. One of `present`, `deleted`.
- `observed_state` (string): Only items with this `observed_state`. One of `pending`, `provisioning`, `active`, `deleting`, `deleted`, `failed`, `unknown`.

Example:

```sh
curl "https://api.pantechdynamics.com/public/v1/networks" \
  -H "Authorization: Bearer $PANTECH_API_KEY"
```

Response `200`:

```json
{
  "data": [
    {
      "id": "net_06gk3x9tq7m2v8r4y1c5d0zp8w",
      "name": "prod",
      "cidr": "10.0.0.0/16",
      "region": "af-abj",
      "zone": "af-abj-1",
      "instance_count": 2,
      "desired_state": "present",
      "observed_state": "active",
      "created_at": "2026-10-03T09:30:00Z",
      "updated_at": "2026-10-03T09:30:00Z"
    }
  ],
  "next_cursor": "eyJhdCI6IjIwMjYtMTAtMDNUMDk6MzA6MDBaIiwiaWQiOiJ2bV8wNmdrIn0"
}
```

Errors:

- `400`: `INVALID_PAGE`: `limit` is not a whole number from 1 to 100. Send a value in that range, or leave it out for 50.
`INVALID_CURSOR`: `cursor` does not belong to this list with these filters. Start again without a cursor.
`INVALID_FILTER`: `q` is longer than 255 characters, or `desired_state` or `observed_state` is not one of its listed values. Fix the parameter named in `detail`.
- `401`: `UNAUTHENTICATED`: the request has no API key, or the key is mistyped, revoked or expired, or its creator has left the organization. Send `Authorization: Bearer PAN_…` with a valid key; create one in the console under Organization › API keys.
- `403`: `INSUFFICIENT_SCOPE`: the API key lacks the scope this endpoint needs (`read` for GET, `write` for changes; an AI app's key also needs `delete` for a destructive call). Use a key with that scope, or reconnect the AI app with "Manage and delete" access.
`FORBIDDEN`: the member who created the key may not do this in the organization. Use a key created by an owner or admin.
`AI_APPS_DISABLED`: the organization has turned AI app access off, and this request was made with an AI app's key or sent by Pantech's MCP server (`Pantech-Client: mcp/…`). An owner can turn it on in the console under Organization › AI apps.
- `429`: `RATE_LIMITED`: this API key, verified user or organization used its request budget for the current window, or this address exceeded an IP/failed-auth limit. Wait `Retry-After` seconds, then retry. For authenticated quota denials, `RateLimit-Scope` identifies the denying quota and `RateLimit-Reset` reports its remaining window in seconds.
- `503`: `SERVICE_UNAVAILABLE`: request quota storage is unavailable. Wait a few seconds, then retry.
## Create a VPC network

```http
POST /public/v1/networks
```

Creates a VPC: a private network of your own, with a CIDR such as `10.0.0.0/16`. Then add subnets to it, and instances or databases to the subnets. A VPC is billed monthly: see *Price a VPC network*.

Returns `202 Accepted` with an `operation_id` (also in the `Location` header). The change happens in the background: poll `GET /public/v1/operations/{operation_id}`, or stream `/events`, until `status` is `succeeded` or `failed`; a failed operation carries a stable `failure.code` and a readable `failure.reason`. The network's id is the operation's `resource_id`.

Send an `Idempotency-Key`. A retry with the same key returns the original operation instead of making the change twice.

Scope: `write`. Send an `Idempotency-Key` header.

Body:

- `name` (string, required): 1 to 255 characters, unique among your VPC networks. At most 255 characters.
- `cidr` (string, required): The VPC's private IPv4 range, e.g. `10.0.0.0/16`. Subnets are carved from it.
- `region` (string): A region from `GET /public/v1/regions` that offers VPC networks. Defaults to the platform's region.

Example:

```sh
curl -X POST "https://api.pantechdynamics.com/public/v1/networks" \
  -H "Authorization: Bearer $PANTECH_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "prod",
    "cidr": "10.0.0.0/16"
  }'
```

Response `202`:

```json
{
  "operation_id": "op_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "resource_id": "net_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "status": "submitting"
}
```

Errors:

- `400`: `IDEMPOTENCY_KEY_REQUIRED`: the `Idempotency-Key` header is missing. Send a new unique value, such as a UUID, with every write.
`INVALID_IDEMPOTENCY_KEY`: the `Idempotency-Key` header is longer than 255 characters. Use a shorter value.
`INVALID_REQUEST_BODY`: the body is not a single valid JSON object. Send one JSON object with the fields documented for this endpoint.
- `401`: `UNAUTHENTICATED`: the request has no API key, or the key is mistyped, revoked or expired, or its creator has left the organization. Send `Authorization: Bearer PAN_…` with a valid key; create one in the console under Organization › API keys.
- `403`: `INSUFFICIENT_SCOPE`: the API key lacks the scope this endpoint needs (`read` for GET, `write` for changes; an AI app's key also needs `delete` for a destructive call). Use a key with that scope, or reconnect the AI app with "Manage and delete" access.
`FORBIDDEN`: the member who created the key may not do this in the organization. Use a key created by an owner or admin.
`AI_APPS_DISABLED`: the organization has turned AI app access off, and this request was made with an AI app's key or sent by Pantech's MCP server (`Pantech-Client: mcp/…`). An owner can turn it on in the console under Organization › AI apps.
- `409`: `NETWORK_NAME_TAKEN`: you already have a VPC with this name. Choose a different name.
`ACCOUNT_SUSPENDED`: an invoice is overdue, or the organization was suspended for non-payment. Pay the outstanding invoice in the console, then retry.
`PROVIDER_ACCOUNT_NOT_READY`: your organization's cloud account is still being set up, which takes a few minutes after sign-up. Retry shortly.
`CONCURRENT_UPDATE`: the resource changed while this request was being processed. Retry the request; if it repeats, read the resource first.
- `413`: `REQUEST_TOO_LARGE`: the body is larger than 64 KiB. Send a smaller request.
- `422`: `VALIDATION_FAILED`: a field is invalid. Each entry of `errors` names the `field` and its `code`:
`name` `REQUIRED` or `NAME_TOO_LONG`: send a name of 1 to 255 characters.
`cidr` `REQUIRED`: send an IPv4 CIDR such as `10.0.0.0/16`.
`region` `REGION_NOT_AVAILABLE`: this region cannot take VPC networks now. Pick one from `GET /public/v1/regions`.
`UNKNOWN_FIELD`: the body has a field this endpoint does not take (named in `field`). Remove it or fix its spelling.
`VALIDATION_FAILED` with no `errors` entry: `cidr` is not a valid IPv4 CIDR.
- `429`: `RATE_LIMITED`: this API key, verified user or organization used its request budget for the current window, or this address exceeded an IP/failed-auth limit. Wait `Retry-After` seconds, then retry. For authenticated quota denials, `RateLimit-Scope` identifies the denying quota and `RateLimit-Reset` reports its remaining window in seconds.
- `503`: `SERVICE_UNAVAILABLE`: request quota storage is unavailable. Wait a few seconds, then retry.
`PROVISIONING_UNAVAILABLE`: the provisioning service is temporarily unavailable. Wait a few seconds, then retry with the same `Idempotency-Key`.
## Price a VPC network

```http
GET /public/v1/networks/quote
```

What one more VPC network costs per month, in your organization's currency. `priced` is false, with an `unpriced_reason`, when no price applies.

Scope: `read`.

Example:

```sh
curl "https://api.pantechdynamics.com/public/v1/networks/quote" \
  -H "Authorization: Bearer $PANTECH_API_KEY"
```

Response `200`:

```json
{
  "currency": "NGN",
  "monthly_minor": 1700000,
  "nominal_month_hours": 730
}
```

Errors:

- `401`: `UNAUTHENTICATED`: the request has no API key, or the key is mistyped, revoked or expired, or its creator has left the organization. Send `Authorization: Bearer PAN_…` with a valid key; create one in the console under Organization › API keys.
- `403`: `INSUFFICIENT_SCOPE`: the API key lacks the scope this endpoint needs (`read` for GET, `write` for changes; an AI app's key also needs `delete` for a destructive call). Use a key with that scope, or reconnect the AI app with "Manage and delete" access.
`FORBIDDEN`: the member who created the key may not do this in the organization. Use a key created by an owner or admin.
`AI_APPS_DISABLED`: the organization has turned AI app access off, and this request was made with an AI app's key or sent by Pantech's MCP server (`Pantech-Client: mcp/…`). An owner can turn it on in the console under Organization › AI apps.
- `404`: `NOT_FOUND`: cost quotes are not available on this platform yet.
- `429`: `RATE_LIMITED`: this API key, verified user or organization used its request budget for the current window, or this address exceeded an IP/failed-auth limit. Wait `Retry-After` seconds, then retry. For authenticated quota denials, `RateLimit-Scope` identifies the denying quota and `RateLimit-Reset` reports its remaining window in seconds.
- `503`: `SERVICE_UNAVAILABLE`: request quota storage is unavailable. Wait a few seconds, then retry.
## Get a VPC network

```http
GET /public/v1/networks/{network_id}
```

One VPC network, with the number of instances in it.

Scope: `read`.

Path parameters:

- `network_id`: The resource's id.

Example:

```sh
curl "https://api.pantechdynamics.com/public/v1/networks/net_06gk3x9tq7m2v8r4y1c5d0zp8w" \
  -H "Authorization: Bearer $PANTECH_API_KEY"
```

Response `200`:

```json
{
  "id": "net_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "name": "prod",
  "cidr": "10.0.0.0/16",
  "region": "af-abj",
  "zone": "af-abj-1",
  "instance_count": 2,
  "desired_state": "present",
  "observed_state": "active",
  "created_at": "2026-10-03T09:30:00Z",
  "updated_at": "2026-10-03T09:30:00Z"
}
```

Errors:

- `401`: `UNAUTHENTICATED`: the request has no API key, or the key is mistyped, revoked or expired, or its creator has left the organization. Send `Authorization: Bearer PAN_…` with a valid key; create one in the console under Organization › API keys.
- `403`: `INSUFFICIENT_SCOPE`: the API key lacks the scope this endpoint needs (`read` for GET, `write` for changes; an AI app's key also needs `delete` for a destructive call). Use a key with that scope, or reconnect the AI app with "Manage and delete" access.
`FORBIDDEN`: the member who created the key may not do this in the organization. Use a key created by an owner or admin.
`AI_APPS_DISABLED`: the organization has turned AI app access off, and this request was made with an AI app's key or sent by Pantech's MCP server (`Pantech-Client: mcp/…`). An owner can turn it on in the console under Organization › AI apps.
- `404`: `RESOURCE_NOT_FOUND`: no VPC network with this id in your organization, or the id is not a VPC network id (`net_…`). Check the id.
- `429`: `RATE_LIMITED`: this API key, verified user or organization used its request budget for the current window, or this address exceeded an IP/failed-auth limit. Wait `Retry-After` seconds, then retry. For authenticated quota denials, `RateLimit-Scope` identifies the denying quota and `RateLimit-Reset` reports its remaining window in seconds.
- `503`: `SERVICE_UNAVAILABLE`: request quota storage is unavailable. Wait a few seconds, then retry.
## Delete a VPC network

```http
DELETE /public/v1/networks/{network_id}
```

Deletes a VPC network. It must hold no instances (in any of its subnets) and no public IPs.

Returns `202 Accepted` with an `operation_id` (also in the `Location` header). The change happens in the background: poll `GET /public/v1/operations/{operation_id}`, or stream `/events`, until `status` is `succeeded` or `failed`; a failed operation carries a stable `failure.code` and a readable `failure.reason`.

Send an `Idempotency-Key`. A retry with the same key returns the original operation instead of making the change twice.

**Scope:** `write`. Destructive: an AI app's key also needs `delete`.

Scope: `write`. Send an `Idempotency-Key` header.

Path parameters:

- `network_id`: The resource's id.

Example:

```sh
curl -X DELETE "https://api.pantechdynamics.com/public/v1/networks/net_06gk3x9tq7m2v8r4y1c5d0zp8w" \
  -H "Authorization: Bearer $PANTECH_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
```

Response `202`:

```json
{
  "operation_id": "op_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "resource_id": "net_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "status": "submitting"
}
```

Errors:

- `400`: `IDEMPOTENCY_KEY_REQUIRED`: the `Idempotency-Key` header is missing. Send a new unique value, such as a UUID, with every write.
`INVALID_IDEMPOTENCY_KEY`: the `Idempotency-Key` header is longer than 255 characters. Use a shorter value.
- `401`: `UNAUTHENTICATED`: the request has no API key, or the key is mistyped, revoked or expired, or its creator has left the organization. Send `Authorization: Bearer PAN_…` with a valid key; create one in the console under Organization › API keys.
- `403`: `INSUFFICIENT_SCOPE`: the API key lacks the scope this endpoint needs (`read` for GET, `write` for changes; an AI app's key also needs `delete` for a destructive call). Use a key with that scope, or reconnect the AI app with "Manage and delete" access.
`FORBIDDEN`: the member who created the key may not do this in the organization. Use a key created by an owner or admin.
`AI_APPS_DISABLED`: the organization has turned AI app access off, and this request was made with an AI app's key or sent by Pantech's MCP server (`Pantech-Client: mcp/…`). An owner can turn it on in the console under Organization › AI apps.
- `404`: `RESOURCE_NOT_FOUND`: no VPC network with this id in your organization, or the id is not a VPC network id (`net_…`). Check the id.
- `409`: `NETWORK_HAS_INSTANCES`: a subnet of this network still has instances. Delete or move them first.
`NETWORK_HAS_PUBLIC_IPS`: the network still holds public IPs. Release them first.
`INVALID_RESOURCE_STATE`: the network cannot do this in its current state, for example while it is being created or deleted. Wait for its current operation to finish, then retry.
`CONCURRENT_UPDATE`: the resource changed while this request was being processed. Retry the request; if it repeats, read the resource first.
- `422`: `VALIDATION_FAILED` with no `errors` entry: the platform refused a value, for example a malformed CIDR or a name longer than 255 characters. Check the request against this page.
- `429`: `RATE_LIMITED`: this API key, verified user or organization used its request budget for the current window, or this address exceeded an IP/failed-auth limit. Wait `Retry-After` seconds, then retry. For authenticated quota denials, `RateLimit-Scope` identifies the denying quota and `RateLimit-Reset` reports its remaining window in seconds.
- `503`: `SERVICE_UNAVAILABLE`: request quota storage is unavailable. Wait a few seconds, then retry.
`PROVISIONING_UNAVAILABLE`: the provisioning service is temporarily unavailable. Wait a few seconds, then retry with the same `Idempotency-Key`.
## List subnets

```http
GET /public/v1/networks/{network_id}/subnets
```

The VPC's subnets.

Scope: `read`.

Path parameters:

- `network_id`: The resource's id.

Query parameters:

- `limit` (integer): Items per page, 1 to 100. Defaults to 50. From 1 to 100. Defaults to `50`.
- `cursor` (string): The previous page's `next_cursor`, to get the next page. Leave out for the first page; keep the other parameters the same.
- `q` (string): Only items whose name contains this text (case-insensitive), at most 255 characters. At most 255 characters.
- `desired_state` (string): Only items with this `desired_state`: `present` or `deleted`. One of `present`, `deleted`.
- `observed_state` (string): Only items with this `observed_state`. One of `pending`, `provisioning`, `active`, `deleting`, `deleted`, `failed`, `unknown`.

Example:

```sh
curl "https://api.pantechdynamics.com/public/v1/networks/net_06gk3x9tq7m2v8r4y1c5d0zp8w/subnets" \
  -H "Authorization: Bearer $PANTECH_API_KEY"
```

Response `200`:

```json
{
  "data": [
    {
      "id": "snet_06gk3x9tq7m2v8r4y1c5d0zp8w",
      "network_id": "net_06gk3x9tq7m2v8r4y1c5d0zp8w",
      "name": "app",
      "cidr": "10.0.1.0/24",
      "region": "af-abj",
      "zone": "af-abj-1",
      "instance_count": 2,
      "desired_state": "present",
      "observed_state": "active",
      "created_at": "2026-10-03T09:30:00Z",
      "updated_at": "2026-10-03T09:30:00Z"
    }
  ],
  "next_cursor": "eyJhdCI6IjIwMjYtMTAtMDNUMDk6MzA6MDBaIiwiaWQiOiJ2bV8wNmdrIn0"
}
```

Errors:

- `400`: `INVALID_PAGE`: `limit` is not a whole number from 1 to 100. Send a value in that range, or leave it out for 50.
`INVALID_CURSOR`: `cursor` does not belong to this list with these filters. Start again without a cursor.
`INVALID_FILTER`: `q` is longer than 255 characters, or `desired_state` or `observed_state` is not one of its listed values. Fix the parameter named in `detail`.
- `401`: `UNAUTHENTICATED`: the request has no API key, or the key is mistyped, revoked or expired, or its creator has left the organization. Send `Authorization: Bearer PAN_…` with a valid key; create one in the console under Organization › API keys.
- `403`: `INSUFFICIENT_SCOPE`: the API key lacks the scope this endpoint needs (`read` for GET, `write` for changes; an AI app's key also needs `delete` for a destructive call). Use a key with that scope, or reconnect the AI app with "Manage and delete" access.
`FORBIDDEN`: the member who created the key may not do this in the organization. Use a key created by an owner or admin.
`AI_APPS_DISABLED`: the organization has turned AI app access off, and this request was made with an AI app's key or sent by Pantech's MCP server (`Pantech-Client: mcp/…`). An owner can turn it on in the console under Organization › AI apps.
- `404`: `RESOURCE_NOT_FOUND`: no VPC network with this id in your organization, or the id is not a VPC network id (`net_…`). Check the id.
- `429`: `RATE_LIMITED`: this API key, verified user or organization used its request budget for the current window, or this address exceeded an IP/failed-auth limit. Wait `Retry-After` seconds, then retry. For authenticated quota denials, `RateLimit-Scope` identifies the denying quota and `RateLimit-Reset` reports its remaining window in seconds.
- `503`: `SERVICE_UNAVAILABLE`: request quota storage is unavailable. Wait a few seconds, then retry.
## Create a subnet

```http
POST /public/v1/networks/{network_id}/subnets
```

Creates a subnet inside the VPC's CIDR, such as `10.0.1.0/24`. Instances and databases are placed in subnets; each subnet has its own firewall rules.

Returns `202 Accepted` with an `operation_id` (also in the `Location` header). The change happens in the background: poll `GET /public/v1/operations/{operation_id}`, or stream `/events`, until `status` is `succeeded` or `failed`; a failed operation carries a stable `failure.code` and a readable `failure.reason`. The subnet's id is the operation's `resource_id`.

Send an `Idempotency-Key`. A retry with the same key returns the original operation instead of making the change twice.

Scope: `write`. Send an `Idempotency-Key` header.

Path parameters:

- `network_id`: The resource's id.

Body:

- `name` (string, required): 1 to 255 characters. At most 255 characters.
- `cidr` (string, required): An IPv4 range inside the VPC's CIDR that does not overlap its other subnets, e.g. `10.0.1.0/24`.

Example:

```sh
curl -X POST "https://api.pantechdynamics.com/public/v1/networks/net_06gk3x9tq7m2v8r4y1c5d0zp8w/subnets" \
  -H "Authorization: Bearer $PANTECH_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "app",
    "cidr": "10.0.1.0/24"
  }'
```

Response `202`:

```json
{
  "operation_id": "op_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "resource_id": "snet_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "status": "submitting"
}
```

Errors:

- `400`: `IDEMPOTENCY_KEY_REQUIRED`: the `Idempotency-Key` header is missing. Send a new unique value, such as a UUID, with every write.
`INVALID_IDEMPOTENCY_KEY`: the `Idempotency-Key` header is longer than 255 characters. Use a shorter value.
`INVALID_REQUEST_BODY`: the body is not a single valid JSON object. Send one JSON object with the fields documented for this endpoint.
- `401`: `UNAUTHENTICATED`: the request has no API key, or the key is mistyped, revoked or expired, or its creator has left the organization. Send `Authorization: Bearer PAN_…` with a valid key; create one in the console under Organization › API keys.
- `403`: `INSUFFICIENT_SCOPE`: the API key lacks the scope this endpoint needs (`read` for GET, `write` for changes; an AI app's key also needs `delete` for a destructive call). Use a key with that scope, or reconnect the AI app with "Manage and delete" access.
`FORBIDDEN`: the member who created the key may not do this in the organization. Use a key created by an owner or admin.
`AI_APPS_DISABLED`: the organization has turned AI app access off, and this request was made with an AI app's key or sent by Pantech's MCP server (`Pantech-Client: mcp/…`). An owner can turn it on in the console under Organization › AI apps.
- `404`: `RESOURCE_NOT_FOUND`: no VPC network with this id in your organization, or the id is not a VPC network id (`net_…`). Check the id.
- `409`: `INVALID_RESOURCE_STATE`: the network cannot do this in its current state, for example while it is being created or deleted. Wait for its current operation to finish, then retry.
`CONCURRENT_UPDATE`: the resource changed while this request was being processed. Retry the request; if it repeats, read the resource first.
- `413`: `REQUEST_TOO_LARGE`: the body is larger than 64 KiB. Send a smaller request.
- `422`: `VALIDATION_FAILED`: a field is invalid. Each entry of `errors` names the `field` and its `code`:
`name` `REQUIRED` or `NAME_TOO_LONG`: send a name of 1 to 255 characters.
`cidr` `REQUIRED`: send an IPv4 CIDR inside the VPC's CIDR.
`UNKNOWN_FIELD`: the body has a field this endpoint does not take (named in `field`). Remove it or fix its spelling.
`VALIDATION_FAILED` with no `errors` entry: `cidr` is not a valid IPv4 CIDR.
- `429`: `RATE_LIMITED`: this API key, verified user or organization used its request budget for the current window, or this address exceeded an IP/failed-auth limit. Wait `Retry-After` seconds, then retry. For authenticated quota denials, `RateLimit-Scope` identifies the denying quota and `RateLimit-Reset` reports its remaining window in seconds.
- `503`: `SERVICE_UNAVAILABLE`: request quota storage is unavailable. Wait a few seconds, then retry.
`PROVISIONING_UNAVAILABLE`: the provisioning service is temporarily unavailable. Wait a few seconds, then retry with the same `Idempotency-Key`.
## Get a subnet

```http
GET /public/v1/subnets/{subnet_id}
```

One subnet, with the number of instances in it.

Scope: `read`.

Path parameters:

- `subnet_id`: The resource's id.

Example:

```sh
curl "https://api.pantechdynamics.com/public/v1/subnets/snet_06gk3x9tq7m2v8r4y1c5d0zp8w" \
  -H "Authorization: Bearer $PANTECH_API_KEY"
```

Response `200`:

```json
{
  "id": "snet_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "network_id": "net_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "name": "app",
  "cidr": "10.0.1.0/24",
  "region": "af-abj",
  "zone": "af-abj-1",
  "instance_count": 2,
  "desired_state": "present",
  "observed_state": "active",
  "created_at": "2026-10-03T09:30:00Z",
  "updated_at": "2026-10-03T09:30:00Z"
}
```

Errors:

- `401`: `UNAUTHENTICATED`: the request has no API key, or the key is mistyped, revoked or expired, or its creator has left the organization. Send `Authorization: Bearer PAN_…` with a valid key; create one in the console under Organization › API keys.
- `403`: `INSUFFICIENT_SCOPE`: the API key lacks the scope this endpoint needs (`read` for GET, `write` for changes; an AI app's key also needs `delete` for a destructive call). Use a key with that scope, or reconnect the AI app with "Manage and delete" access.
`FORBIDDEN`: the member who created the key may not do this in the organization. Use a key created by an owner or admin.
`AI_APPS_DISABLED`: the organization has turned AI app access off, and this request was made with an AI app's key or sent by Pantech's MCP server (`Pantech-Client: mcp/…`). An owner can turn it on in the console under Organization › AI apps.
- `404`: `RESOURCE_NOT_FOUND`: no subnet with this id in your organization, or the id is not a subnet id (`snet_…`). Check the id.
- `429`: `RATE_LIMITED`: this API key, verified user or organization used its request budget for the current window, or this address exceeded an IP/failed-auth limit. Wait `Retry-After` seconds, then retry. For authenticated quota denials, `RateLimit-Scope` identifies the denying quota and `RateLimit-Reset` reports its remaining window in seconds.
- `503`: `SERVICE_UNAVAILABLE`: request quota storage is unavailable. Wait a few seconds, then retry.
## Delete a subnet

```http
DELETE /public/v1/subnets/{subnet_id}
```

Deletes a subnet. It must hold no instances or databases.

Returns `202 Accepted` with an `operation_id` (also in the `Location` header). The change happens in the background: poll `GET /public/v1/operations/{operation_id}`, or stream `/events`, until `status` is `succeeded` or `failed`; a failed operation carries a stable `failure.code` and a readable `failure.reason`.

Send an `Idempotency-Key`. A retry with the same key returns the original operation instead of making the change twice.

**Scope:** `write`. Destructive: an AI app's key also needs `delete`.

Scope: `write`. Send an `Idempotency-Key` header.

Path parameters:

- `subnet_id`: The resource's id.

Example:

```sh
curl -X DELETE "https://api.pantechdynamics.com/public/v1/subnets/snet_06gk3x9tq7m2v8r4y1c5d0zp8w" \
  -H "Authorization: Bearer $PANTECH_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
```

Response `202`:

```json
{
  "operation_id": "op_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "resource_id": "snet_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "status": "submitting"
}
```

Errors:

- `400`: `IDEMPOTENCY_KEY_REQUIRED`: the `Idempotency-Key` header is missing. Send a new unique value, such as a UUID, with every write.
`INVALID_IDEMPOTENCY_KEY`: the `Idempotency-Key` header is longer than 255 characters. Use a shorter value.
- `401`: `UNAUTHENTICATED`: the request has no API key, or the key is mistyped, revoked or expired, or its creator has left the organization. Send `Authorization: Bearer PAN_…` with a valid key; create one in the console under Organization › API keys.
- `403`: `INSUFFICIENT_SCOPE`: the API key lacks the scope this endpoint needs (`read` for GET, `write` for changes; an AI app's key also needs `delete` for a destructive call). Use a key with that scope, or reconnect the AI app with "Manage and delete" access.
`FORBIDDEN`: the member who created the key may not do this in the organization. Use a key created by an owner or admin.
`AI_APPS_DISABLED`: the organization has turned AI app access off, and this request was made with an AI app's key or sent by Pantech's MCP server (`Pantech-Client: mcp/…`). An owner can turn it on in the console under Organization › AI apps.
- `404`: `RESOURCE_NOT_FOUND`: no subnet with this id in your organization, or the id is not a subnet id (`snet_…`). Check the id.
- `409`: `INVALID_RESOURCE_STATE`: the subnet still has instances or databases, or is already being deleted. Delete them first.
`SUBNET_HAS_KUBERNETES_CLUSTERS`: Kubernetes clusters still run in this subnet. Delete them first.
`CONCURRENT_UPDATE`: the resource changed while this request was being processed. Retry the request; if it repeats, read the resource first.
- `422`: `VALIDATION_FAILED` with no `errors` entry: the platform refused a value, for example a malformed CIDR or a name longer than 255 characters. Check the request against this page.
- `429`: `RATE_LIMITED`: this API key, verified user or organization used its request budget for the current window, or this address exceeded an IP/failed-auth limit. Wait `Retry-After` seconds, then retry. For authenticated quota denials, `RateLimit-Scope` identifies the denying quota and `RateLimit-Reset` reports its remaining window in seconds.
- `503`: `SERVICE_UNAVAILABLE`: request quota storage is unavailable. Wait a few seconds, then retry.
`PROVISIONING_UNAVAILABLE`: the provisioning service is temporarily unavailable. Wait a few seconds, then retry with the same `Idempotency-Key`.
## List a subnet's firewall rules

```http
GET /public/v1/subnets/{subnet_id}/firewall-rules
```

The subnet's firewall rules, in evaluation order, and the platform's fixed rules around them (`system_rules`), which always apply.

Scope: `read`.

Path parameters:

- `subnet_id`: The resource's id.

Example:

```sh
curl "https://api.pantechdynamics.com/public/v1/subnets/snet_06gk3x9tq7m2v8r4y1c5d0zp8w/firewall-rules" \
  -H "Authorization: Bearer $PANTECH_API_KEY"
```

Response `200`:

```json
{
  "data": [
    {
      "id": "aclr_06gk3x9tq7m2v8r4y1c5d0zp8w",
      "subnet_id": "snet_06gk3x9tq7m2v8r4y1c5d0zp8w",
      "number": 100,
      "direction": "ingress",
      "protocol": "tcp",
      "port_start": 443,
      "port_end": 443,
      "icmp_type": 1,
      "icmp_code": 1,
      "cidr": "0.0.0.0/0",
      "action": "allow",
      "desired_state": "present",
      "observed_state": "active",
      "created_at": "2026-10-03T09:30:00Z",
      "updated_at": "2026-10-03T09:30:00Z"
    }
  ],
  "next_cursor": null,
  "system_rules": [
    {
      "number": 100,
      "direction": "ingress",
      "protocol": "tcp",
      "port_start": 443,
      "port_end": 443,
      "icmp_type": 1,
      "icmp_code": 1,
      "cidr": "0.0.0.0/0",
      "action": "allow"
    }
  ]
}
```

Errors:

- `401`: `UNAUTHENTICATED`: the request has no API key, or the key is mistyped, revoked or expired, or its creator has left the organization. Send `Authorization: Bearer PAN_…` with a valid key; create one in the console under Organization › API keys.
- `403`: `INSUFFICIENT_SCOPE`: the API key lacks the scope this endpoint needs (`read` for GET, `write` for changes; an AI app's key also needs `delete` for a destructive call). Use a key with that scope, or reconnect the AI app with "Manage and delete" access.
`FORBIDDEN`: the member who created the key may not do this in the organization. Use a key created by an owner or admin.
`AI_APPS_DISABLED`: the organization has turned AI app access off, and this request was made with an AI app's key or sent by Pantech's MCP server (`Pantech-Client: mcp/…`). An owner can turn it on in the console under Organization › AI apps.
- `404`: `RESOURCE_NOT_FOUND`: no subnet with this id in your organization, or the id is not a subnet id (`snet_…`). Check the id.
`NOT_FOUND`: firewall rules are not offered on this platform yet.
- `409`: `FIREWALL_RULES_NOT_SUPPORTED`: firewall rules apply to VPC subnets only. Standard instances use security groups.
- `429`: `RATE_LIMITED`: this API key, verified user or organization used its request budget for the current window, or this address exceeded an IP/failed-auth limit. Wait `Retry-After` seconds, then retry. For authenticated quota denials, `RateLimit-Scope` identifies the denying quota and `RateLimit-Reset` reports its remaining window in seconds.
- `503`: `SERVICE_UNAVAILABLE`: request quota storage is unavailable. Wait a few seconds, then retry.
## Add a firewall rule

```http
POST /public/v1/subnets/{subnet_id}/firewall-rules
```

Adds a rule to the subnet's firewall. Rules are evaluated by `number`, lowest first, and the first match decides; traffic no rule allows is dropped. A rule applies to the whole subnet. Defaults: `direction` `ingress`, `action` `allow`, `port_end` equal to `port_start`.

Returns `202 Accepted` with an `operation_id` (also in the `Location` header). The change happens in the background: poll `GET /public/v1/operations/{operation_id}`, or stream `/events`, until `status` is `succeeded` or `failed`; a failed operation carries a stable `failure.code` and a readable `failure.reason`. The rule's id is the operation's `resource_id`.

Send an `Idempotency-Key`. A retry with the same key returns the original operation instead of making the change twice.

Scope: `write`. Send an `Idempotency-Key` header.

Path parameters:

- `subnet_id`: The resource's id.

Body:

- `number` (integer, required): Evaluation order, 100 to 9999, unique on the subnet; lower numbers are evaluated first and the first match decides. From 100 to 9999.
- `direction` (string): `ingress` (traffic into the subnet) or `egress` (traffic out of it). Defaults to `ingress`. One of `ingress`, `egress`. Defaults to `ingress`.
- `protocol` (string, required): `tcp`, `udp`, `icmp` or `all`. One of `tcp`, `udp`, `icmp`, `all`.
- `port_start` (integer): First port, 1 to 65535. For `tcp` and `udp` only; leave out for `icmp` and `all`.
- `port_end` (integer): Last port, 1 to 65535, at least `port_start`. Defaults to `port_start` (one port).
- `icmp_type` (integer): ICMP type, for `icmp` only, e.g. `8` for echo request. Leave out for every type.
- `icmp_code` (integer): ICMP code, for `icmp` only. Leave out for every code.
- `cidr` (string, required): One IPv4 CIDR: the source for `ingress`, the destination for `egress`. `0.0.0.0/0` means anywhere.
- `action` (string): `allow` or `deny`. Defaults to `allow`. One of `allow`, `deny`. Defaults to `allow`.

Example:

```sh
curl -X POST "https://api.pantechdynamics.com/public/v1/subnets/snet_06gk3x9tq7m2v8r4y1c5d0zp8w/firewall-rules" \
  -H "Authorization: Bearer $PANTECH_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "number": 100,
    "protocol": "tcp",
    "cidr": "203.0.113.0/24"
  }'
```

Response `202`:

```json
{
  "operation_id": "op_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "resource_id": "aclr_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "status": "submitting"
}
```

Errors:

- `400`: `IDEMPOTENCY_KEY_REQUIRED`: the `Idempotency-Key` header is missing. Send a new unique value, such as a UUID, with every write.
`INVALID_IDEMPOTENCY_KEY`: the `Idempotency-Key` header is longer than 255 characters. Use a shorter value.
`INVALID_REQUEST_BODY`: the body is not a single valid JSON object. Send one JSON object with the fields documented for this endpoint.
- `401`: `UNAUTHENTICATED`: the request has no API key, or the key is mistyped, revoked or expired, or its creator has left the organization. Send `Authorization: Bearer PAN_…` with a valid key; create one in the console under Organization › API keys.
- `403`: `INSUFFICIENT_SCOPE`: the API key lacks the scope this endpoint needs (`read` for GET, `write` for changes; an AI app's key also needs `delete` for a destructive call). Use a key with that scope, or reconnect the AI app with "Manage and delete" access.
`FORBIDDEN`: the member who created the key may not do this in the organization. Use a key created by an owner or admin.
`AI_APPS_DISABLED`: the organization has turned AI app access off, and this request was made with an AI app's key or sent by Pantech's MCP server (`Pantech-Client: mcp/…`). An owner can turn it on in the console under Organization › AI apps.
- `404`: `RESOURCE_NOT_FOUND`: no subnet with this id in your organization, or the id is not a subnet id (`snet_…`). Check the id.
`NOT_FOUND`: firewall rules are not offered on this platform yet.
- `409`: `FIREWALL_RULES_NOT_SUPPORTED`: firewall rules apply to VPC subnets only. Standard instances use security groups.
`INVALID_RESOURCE_STATE`: the subnet cannot do this in its current state, for example while it is being created or deleted. Wait for its current operation to finish, then retry.
`CONCURRENT_UPDATE`: the resource changed while this request was being processed. Retry the request; if it repeats, read the resource first.
- `413`: `REQUEST_TOO_LARGE`: the body is larger than 64 KiB. Send a smaller request.
- `422`: `VALIDATION_FAILED`: a field is invalid. Each entry of `errors` names the `field` and its `code`:
`protocol` or `cidr` `REQUIRED`: send both.
`number` `INVALID_RULE_NUMBER`: use 100 to 9999.
`number` `RULE_NUMBER_TAKEN`: another rule on this subnet has this number. Choose another.
`port_start` `INVALID_PORTS`: send ports 1 to 65535 for `tcp` or `udp`, and leave them out for `icmp` or `all`.
`protocol` `INVALID_FIREWALL_RULE`: `direction`, `protocol`, `action` or the ICMP fields are not valid values.
`UNKNOWN_FIELD`: the body has a field this endpoint does not take (named in `field`). Remove it or fix its spelling.
- `429`: `RATE_LIMITED`: this API key, verified user or organization used its request budget for the current window, or this address exceeded an IP/failed-auth limit. Wait `Retry-After` seconds, then retry. For authenticated quota denials, `RateLimit-Scope` identifies the denying quota and `RateLimit-Reset` reports its remaining window in seconds.
- `503`: `SERVICE_UNAVAILABLE`: request quota storage is unavailable. Wait a few seconds, then retry.
`PROVISIONING_UNAVAILABLE`: the provisioning service is temporarily unavailable. Wait a few seconds, then retry with the same `Idempotency-Key`.
## Get a firewall rule

```http
GET /public/v1/subnets/{subnet_id}/firewall-rules/{rule_id}
```

One firewall rule on the subnet.

Scope: `read`.

Path parameters:

- `subnet_id`: The resource's id.
- `rule_id`: The rule's id (`aclr_...` for a firewall rule, `pfr_...` for a port forwarding rule).

Example:

```sh
curl "https://api.pantechdynamics.com/public/v1/subnets/snet_06gk3x9tq7m2v8r4y1c5d0zp8w/firewall-rules/aclr_06gk3x9tq7m2v8r4y1c5d0zp8w" \
  -H "Authorization: Bearer $PANTECH_API_KEY"
```

Response `200`:

```json
{
  "id": "aclr_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "subnet_id": "snet_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "number": 100,
  "direction": "ingress",
  "protocol": "tcp",
  "port_start": 443,
  "port_end": 443,
  "icmp_type": 1,
  "icmp_code": 1,
  "cidr": "0.0.0.0/0",
  "action": "allow",
  "desired_state": "present",
  "observed_state": "active",
  "created_at": "2026-10-03T09:30:00Z",
  "updated_at": "2026-10-03T09:30:00Z"
}
```

Errors:

- `401`: `UNAUTHENTICATED`: the request has no API key, or the key is mistyped, revoked or expired, or its creator has left the organization. Send `Authorization: Bearer PAN_…` with a valid key; create one in the console under Organization › API keys.
- `403`: `INSUFFICIENT_SCOPE`: the API key lacks the scope this endpoint needs (`read` for GET, `write` for changes; an AI app's key also needs `delete` for a destructive call). Use a key with that scope, or reconnect the AI app with "Manage and delete" access.
`FORBIDDEN`: the member who created the key may not do this in the organization. Use a key created by an owner or admin.
`AI_APPS_DISABLED`: the organization has turned AI app access off, and this request was made with an AI app's key or sent by Pantech's MCP server (`Pantech-Client: mcp/…`). An owner can turn it on in the console under Organization › AI apps.
- `404`: `RESOURCE_NOT_FOUND`: no rule with this id on this subnet, or no such subnet in your organization. Check both ids.
`NOT_FOUND`: firewall rules are not offered on this platform yet.
- `409`: `FIREWALL_RULES_NOT_SUPPORTED`: firewall rules apply to VPC subnets only. Standard instances use security groups.
- `429`: `RATE_LIMITED`: this API key, verified user or organization used its request budget for the current window, or this address exceeded an IP/failed-auth limit. Wait `Retry-After` seconds, then retry. For authenticated quota denials, `RateLimit-Scope` identifies the denying quota and `RateLimit-Reset` reports its remaining window in seconds.
- `503`: `SERVICE_UNAVAILABLE`: request quota storage is unavailable. Wait a few seconds, then retry.
## Delete a firewall rule

```http
DELETE /public/v1/firewall-rules/{rule_id}
```

Deletes one subnet firewall rule. Traffic it allowed is dropped once the operation succeeds, unless another rule allows it.

Returns `202 Accepted` with an `operation_id` (also in the `Location` header). The change happens in the background: poll `GET /public/v1/operations/{operation_id}`, or stream `/events`, until `status` is `succeeded` or `failed`; a failed operation carries a stable `failure.code` and a readable `failure.reason`.

Send an `Idempotency-Key`. A retry with the same key returns the original operation instead of making the change twice.

**Scope:** `write`. Destructive: an AI app's key also needs `delete`.

Scope: `write`. Send an `Idempotency-Key` header.

Path parameters:

- `rule_id`: The rule's id (`aclr_...` for a firewall rule, `pfr_...` for a port forwarding rule).

Example:

```sh
curl -X DELETE "https://api.pantechdynamics.com/public/v1/firewall-rules/aclr_06gk3x9tq7m2v8r4y1c5d0zp8w" \
  -H "Authorization: Bearer $PANTECH_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
```

Response `202`:

```json
{
  "operation_id": "op_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "resource_id": "aclr_06gk3x9tq7m2v8r4y1c5d0zp8w",
  "status": "submitting"
}
```

Errors:

- `400`: `IDEMPOTENCY_KEY_REQUIRED`: the `Idempotency-Key` header is missing. Send a new unique value, such as a UUID, with every write.
`INVALID_IDEMPOTENCY_KEY`: the `Idempotency-Key` header is longer than 255 characters. Use a shorter value.
- `401`: `UNAUTHENTICATED`: the request has no API key, or the key is mistyped, revoked or expired, or its creator has left the organization. Send `Authorization: Bearer PAN_…` with a valid key; create one in the console under Organization › API keys.
- `403`: `INSUFFICIENT_SCOPE`: the API key lacks the scope this endpoint needs (`read` for GET, `write` for changes; an AI app's key also needs `delete` for a destructive call). Use a key with that scope, or reconnect the AI app with "Manage and delete" access.
`FORBIDDEN`: the member who created the key may not do this in the organization. Use a key created by an owner or admin.
`AI_APPS_DISABLED`: the organization has turned AI app access off, and this request was made with an AI app's key or sent by Pantech's MCP server (`Pantech-Client: mcp/…`). An owner can turn it on in the console under Organization › AI apps.
- `404`: `RESOURCE_NOT_FOUND`: no firewall rule with this id in your organization, or the id is not a firewall rule id (`aclr_…`). Check the id.
`NOT_FOUND`: firewall rules are not offered on this platform yet.
- `409`: `INVALID_RESOURCE_STATE`: the firewall rule cannot do this in its current state, for example while it is being created or deleted. Wait for its current operation to finish, then retry.
`CONCURRENT_UPDATE`: the resource changed while this request was being processed. Retry the request; if it repeats, read the resource first.
- `422`: `VALIDATION_FAILED` with no `errors` entry: the platform refused the request, for example because the resource has already been deleted. Read the resource to check its state.
- `429`: `RATE_LIMITED`: this API key, verified user or organization used its request budget for the current window, or this address exceeded an IP/failed-auth limit. Wait `Retry-After` seconds, then retry. For authenticated quota denials, `RateLimit-Scope` identifies the denying quota and `RateLimit-Reset` reports its remaining window in seconds.
- `503`: `SERVICE_UNAVAILABLE`: request quota storage is unavailable. Wait a few seconds, then retry.
`PROVISIONING_UNAVAILABLE`: the provisioning service is temporarily unavailable. Wait a few seconds, then retry with the same `Idempotency-Key`.
