# Catalogue

Regions, plans, images and disk offerings: what you can create, and what it costs.

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

Read the catalogue to find the slugs you create resources with: a plan's `slug` is an instance's `plan_slug`, an image's `slug` its `image_slug`, a disk offering's `slug` a volume's `disk_offering_slug`. Prices are integers in minor units (kobo for NGN, cents for USD).

Endpoints:

- `GET /public/v1/regions`: List regions
- `GET /public/v1/plans`: List plans
- `GET /public/v1/images`: List images
- `GET /public/v1/disk-offerings`: List disk offerings
- `GET /public/v1/disk-offerings/{slug}/quote`: Price a volume
- `POST /public/v1/pricing/estimate`: Estimate a monthly bill

## List regions

```http
GET /public/v1/regions
```

Regions and their zones, and whether each zone can take standard instances or VPC networks right now (`available`, with an `unavailable_reason` when not). Use a zone as `zone_id` for a database, or a region as `region` elsewhere.

Scope: `read`.

Example:

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

Response `200`:

```json
{
  "data": [
    {
      "code": "af-abj",
      "name": "Abuja",
      "placements": [
        {
          "kind": "standard",
          "zone": "af-abj-1",
          "available": true,
          "unavailable_reason": null,
          "private_network_cidr": "10.250.0.0/20"
        }
      ]
    }
  ],
  "next_cursor": null
}
```

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.
- `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.
## List plans

```http
GET /public/v1/plans
```

Instance sizes (vCPU, memory and disk), priced in your organization's currency. Use a `slug` as `plan_slug` for an instance or a database. Send `placement=vpc` to price a VPC instance (no public address of its own), or leave it out for a standard instance.

Scope: `read`.

Query parameters:

- `placement` (string): Price for standard instances or VPC instances. One of `standard`, `vpc`. Defaults to `standard`.

Example:

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

Response `200`:

```json
{
  "data": [
    {
      "id": "id",
      "slug": "slug",
      "name": "web-1",
      "vcpu": 2,
      "memory_mb": 4096,
      "disk_gb": 80,
      "price": {
        "currency": "NGN",
        "monthly_estimate_minor": 3760000,
        "storage_floor_minor": 460000,
        "initial_payment_minor": 1504000
      },
      "unpriced_reason": null
    }
  ],
  "next_cursor": null
}
```

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.
- `422`: `VALIDATION_FAILED`: a field is invalid. Each entry of `errors` names the `field` and its `code`:
`placement` `INVALID_PLACEMENT`: use `standard` or `vpc`.
- `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.
## List images

```http
GET /public/v1/images
```

Operating systems you can install on an instance, and the zones each runs in. Use a `slug` as `image_slug` in *Create an instance* or *Rebuild an instance*.

Encrypted images (`encrypted: true`) appear only for organizations they are enabled for; elsewhere their slug is refused as `IMAGE_NOT_FOUND`.

Scope: `read`.

Example:

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

Response `200`:

```json
{
  "data": [
    {
      "id": "id",
      "slug": "slug",
      "name": "web-1",
      "version": "version",
      "zones": [
        "af-abj-1"
      ],
      "encrypted": true,
      "encrypted_variant_of": "encrypted-variant-of"
    }
  ],
  "next_cursor": null
}
```

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.
- `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.
## List disk offerings

```http
GET /public/v1/disk-offerings
```

Volume types and their hourly prices. Use a `slug` as `disk_offering_slug` in *Create a volume*; for an offering with `custom_size: true`, also send `size_gb`.

Scope: `read`.

Example:

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

Response `200`:

```json
{
  "data": [
    {
      "slug": "slug",
      "name": "web-1",
      "size_gb": 20,
      "custom_size": false,
      "storage_type": "shared",
      "currency": "NGN",
      "hourly_price_minor": 640
    }
  ],
  "next_cursor": null
}
```

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.
- `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.
## Price a volume

```http
GET /public/v1/disk-offerings/{slug}/quote
```

The monthly price of one volume of this offering. `size_gb` is required for a custom-size offering and ignored otherwise. Use it to show a price before *Create a volume*.

Scope: `read`.

Path parameters:

- `slug`: The disk offering's slug.

Query parameters:

- `size_gb` (integer): At least 1.

Example:

```sh
curl "https://api.pantechdynamics.com/public/v1/disk-offerings/medium-20gb/quote" \
  -H "Authorization: Bearer $PANTECH_API_KEY"
```

Response `200`:

```json
{
  "disk_offering_slug": "medium-20gb",
  "size_gb": 20,
  "currency": "NGN",
  "hourly_price_minor": 640,
  "monthly_price_minor": 467200
}
```

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 active disk offering has this slug. Pick one from `GET /public/v1/disk-offerings`.
- `422`: `VALIDATION_FAILED`: a field is invalid. Each entry of `errors` names the `field` and its `code`:
`size_gb` `INVALID_SIZE`: send a whole number of GB, at least 1.
`size_gb` `SIZE_REQUIRED`: this offering is custom-size, so `size_gb` is required.
- `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.
## Estimate a monthly bill

```http
POST /public/v1/pricing/estimate
```

Prices a whole configuration before you build it: machines by plan and running hours, extra storage, VPC networks and snapshot storage. Nothing is created and nothing is charged, so no `Idempotency-Key` is needed.

`pricing_complete` is false when any line could not be priced; that line has `priced: false` and an `unpriced_reason`.

Scope: `read`.

Body:

- `currency` (string, required): The currency to price in: `NGN` or `USD`. One of `NGN`, `USD`.
- `machines` (array of object): Instances to price: up to 50 lines, each a plan, a quantity and running hours per month. At most 50 items.
  - `plan_slug` (string, required)
  - `quantity` (integer, required): At least 1.
  - `running_hours` (integer, required): From 0 to 730.
  - `placement` (string): One of `standard`, `vpc`.
- `extra_storage_gb` (integer): Extra volume storage in GB. At least 0.
- `network_count` (integer): Number of VPC networks. At least 0.
- `snapshot_gb` (integer): Snapshot storage in GB. At least 0.

Example:

```sh
curl -X POST "https://api.pantechdynamics.com/public/v1/pricing/estimate" \
  -H "Authorization: Bearer $PANTECH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "currency": "NGN",
    "machines": [
      {
        "plan_slug": "starter",
        "quantity": 2,
        "running_hours": 730,
        "placement": "standard"
      }
    ]
  }'
```

Response `200`:

```json
{
  "currency": "NGN",
  "nominal_month_hours": 730,
  "machines": [
    {
      "plan_slug": "starter",
      "quantity": 2,
      "running_hours": 730,
      "priced": true,
      "unpriced_reason": null,
      "unit_monthly_estimate_minor": 1,
      "total_monthly_estimate_minor": 1
    }
  ],
  "extra_storage_gb": {
    "requested": 0,
    "priced": true,
    "unpriced_reason": null,
    "amount_minor": 1059200
  },
  "networks": {
    "requested": 0,
    "priced": true,
    "unpriced_reason": null,
    "amount_minor": 1059200
  },
  "snapshot_gb": {
    "requested": 0,
    "priced": true,
    "unpriced_reason": null,
    "amount_minor": 1059200
  },
  "pricing_complete": true,
  "priced_subtotal_minor": 1
}
```

Errors:

- `400`: `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.
- `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`:
`currency` `UNSUPPORTED_CURRENCY`: use `NGN` or `USD`.
`machines` `TOO_MANY_MACHINES`: at most 50 machine lines.
`machines` `INVALID_MACHINE`: each machine needs a `plan_slug`, a `quantity` above 0 and 0 to 730 `running_hours`.
`placement` `INVALID_PLACEMENT`: use `standard` or `vpc`.
`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.
