Clusters

The clusters endpoint allows you to retrieve information about clusters as well as provision new ones and delete existing clusters.

Prior to using any of these endpoints, take a look at the Getting Started section within the API reference to understand how to create your long lived API key and retrieve a short lived key to be able to execute operations against the API.

Listing clusters

Generic listing

The /clusters endpoint itself will list from the Personal team.

Status code: 200 OK

{
  "clusters": [
    {
      "id": "sajm7dlmcbgpnlf2naqcyx62xm",
      "cpu": 1,
      "disk_usage": null,
      "cluster_id": null,
      "created_at": "2021-10-16T14:12:25.223464Z",
      "is_ha": false,
      "maintenance_window_start": null,
      "major_version": 14,
      "memory": 2,
      "name": "beefy-bird-991",
      "network_id": "idylvx3kcfd6zjblpwn2mhxw7q",
      "plan_id": "hobby-2",
      "postgres_version_id": "pznxu5pmq5fcxhbjxiqlunliri",
      "provider_id": "aws",
      "region_id": "ca-central-1",
      "replicas": [
        {
          "id": "7gp7nmozeng6tdvzjxtwlnbj3a",
          "cpu": 1,
          "disk_usage": null,
          "cluster_id": "sajm7dlmcbgpnlf2naqcyx62xm",
          "created_at": "2021-10-16T14:12:39.82442Z",
          "is_ha": false,
          "maintenance_window_start": null,
          "major_version": 14,
          "memory": 2,
          "name": "beefy-bird-991-replica",
          "network_id": "idylvx3kcfd6zjblpwn2mhxw7q",
          "plan_id": "hobby-2",
          "postgres_version_id": "pznxu5pmq5fcxhbjxiqlunliri",
          "provider_id": "aws",
          "region_id": "ca-central-1",
          "replicas": null,
          "storage": 100,
          "team_id": "yu75urhhxbhztiimoqpmrvmyzi",
          "updated_at": "2021-10-16T14:12:39.82442Z"
        }
      ],
      "storage": 100,
      "team_id": "yu75urhhxbhztiimoqpmrvmyzi",
      "updated_at": "2021-10-16T14:12:31.869041Z"
    },
    {
      "id": "thatmhx5vndt5c6wijo7s6w45m",
      "cpu": 1,
      "disk_usage": {
        "disk_available_mb": 94935,
        "disk_total_size_mb": 100216,
        "disk_used_mb": 149
      },
      "cluster_id": null,
      "created_at": "2021-09-08T00:11:37.990338Z",
      "is_ha": false,
      "maintenance_window_start": null,
      "major_version": 13,
      "memory": 2,
      "name": "myCluster",
      "network_id": "63dkgt5warey7lhtbduwhqznii",
      "plan_id": "hobby-2",
      "postgres_version_id": "6ibnzig5avgutdgdzei2jwvvt4",
      "provider_id": "azure",
      "region_id": "eastus2",
      "replicas": null,
      "storage": 100,
      "team_id": "yu75urhhxbhztiimoqpmrvmyzi",
      "updated_at": "2021-10-16T01:05:49.673384Z"
    }
  ],
  "total_count": 2,
  "total_pages": 1
}

Team-specific listing

To retrieve the list of clusters that exist for a specific team, you should hit the standard clusters endpoint followed by the team ID as a query parameter:

GET /clusters?team_id={team_id}

This will provide all clusters that exist within that team.

Status code: 200 OK

{
  "clusters": [
    {
      "id": "sajm7dlmcbgpnlf2naqcyx62xm",
      "cpu": 1,
      "disk_usage": null,
      "cluster_id": null,
      "created_at": "2021-10-16T14:12:25.223464Z",
      "is_ha": false,
      "maintenance_window_start": null,
      "major_version": 14,
      "memory": 2,
      "name": "beefy-bird-991",
      "network_id": "idylvx3kcfd6zjblpwn2mhxw7q",
      "plan_id": "hobby-2",
      "postgres_version_id": "pznxu5pmq5fcxhbjxiqlunliri",
      "provider_id": "aws",
      "region_id": "ca-central-1",
      "replicas": [
        {
          "id": "7gp7nmozeng6tdvzjxtwlnbj3a",
          "cpu": 1,
          "disk_usage": null,
          "cluster_id": "sajm7dlmcbgpnlf2naqcyx62xm",
          "created_at": "2021-10-16T14:12:39.82442Z",
          "is_ha": false,
          "maintenance_window_start": null,
          "major_version": 14,
          "memory": 2,
          "name": "beefy-bird-991-replica",
          "network_id": "idylvx3kcfd6zjblpwn2mhxw7q",
          "plan_id": "hobby-2",
          "postgres_version_id": "pznxu5pmq5fcxhbjxiqlunliri",
          "provider_id": "aws",
          "region_id": "ca-central-1",
          "replicas": null,
          "storage": 100,
          "team_id": "yu75urhhxbhztiimoqpmrvmyzi",
          "updated_at": "2021-10-16T14:12:39.82442Z"
        }
      ],
      "storage": 100,
      "team_id": "yu75urhhxbhztiimoqpmrvmyzi",
      "updated_at": "2021-10-16T14:12:31.869041Z"
    },
    {
      "id": "thatmhx5vndt5c6wijo7s6w45m",
      "cpu": 1,
      "disk_usage": {
        "disk_available_mb": 94935,
        "disk_total_size_mb": 100216,
        "disk_used_mb": 149
      },
      "cluster_id": null,
      "created_at": "2021-09-08T00:11:37.990338Z",
      "is_ha": false,
      "maintenance_window_start": null,
      "major_version": 13,
      "memory": 2,
      "name": "myCluster",
      "network_id": "63dkgt5warey7lhtbduwhqznii",
      "plan_id": "hobby-2",
      "postgres_version_id": "6ibnzig5avgutdgdzei2jwvvt4",
      "provider_id": "azure",
      "region_id": "eastus2",
      "replicas": null,
      "storage": 100,
      "team_id": "yu75urhhxbhztiimoqpmrvmyzi",
      "updated_at": "2021-10-16T01:05:49.673384Z"
    }
  ],
  "total_count": 2,
  "total_pages": 1
}

Upgrade Object

{
  "operations": [
    {
      "flavor": null,
      "state": null
    }
  ]
}
Attribute Type Description
flavor string The kind of upgrade. One of: ha_change, major_version_upgrade, or resize.
required
state string The state of the ongoing resize. One of ready, scheduled, in_progress, or failing_over for a major version upgrade or resize. One of enabling_ha, waiting_for_ha_standby or disabling_ha for an HA change.

Disk Usage Object

{
  "disk_usage": {
    "disk_available_mb": 0,
    "disk_total_size_mb": 0,
    "disk_used_mb": 0
  }
}
Attribute Type Description
disk_available_mb integer Available disk size in megabytes
disk_total_size_mb integer Total size in megabytes
disk_used_mb integer Disk used in megabytes

Role Object

{
  "name": "",
  "password": "",
  "uri": ""
}

Clusters object

Attribute Type Description
id string Unique identifier for the cluster
disk_usage Disk Usage see Disk Usage Object
cluster_id string Unique identifier for cluster
team_id string Unique identifier for the team
provider_id string Unique identifier for provider
region_id string Unique identifier for region
created_at string Date/time of when the cluster was created, in RFC3339 format
maintenance_window_start string The hour of day which a maintenance window can possibly start. This should be an integer from 0 to 23 representing the hour of day which maintenance is allowed to start, with 0 representing midnight UTC. Maintenance windows are typically three hours long starting from this hour. A null value means that no explicit maintenance window has been set and that maintenance is allowed to occur at any time.
updated_at string Date/time of when the cluster was last created, in RFC3339 format
name string Name of cluster
major_version integer PostgreSQL major version number
network_id string Unique id for network see #team for detail
plan_id string Unique id for plan
postgres_version_id string Unique id for postgres version
storage integer Storage in GB
cpu integer Number of vCores
memory integer Memory in GB
is_ha boolean Whether high availability is enabled for cluster
replicas array of objects Read replicas of cluster

Replicas object

The replicas object has the same attributes as the parent cluster object.

Retrieving cluster details

Details about a specific cluster can be retrieved using the GET /clusters/{cluster_id} endpoint. Note there are two duplicate entries here, 1 has a key, the other does not

Status code: 200 OK

{
  "id": "thatmhx5vndt5c6wijo7s6w45m",
  "cpu": 1,
  "disk_usage": {
    "disk_available_mb": 94935,
    "disk_total_size_mb": 100216,
    "disk_used_mb": 149
  },
  "cluster_id": null,
  "created_at": "2021-09-08T00:11:37.990338Z",
  "is_ha": false,
  "maintenance_window_start": null,
  "major_version": 13,
  "memory": 2,
  "name": "myCluster",
  "network_id": "63dkgt5warey7lhtbduwhqznii",
  "plan_id": "hobby-2",
  "postgres_version_id": "6ibnzig5avgutdgdzei2jwvvt4",
  "provider_id": "azure",
  "region_id": "eastus2",
  "replicas": [],
  "storage": 100,
  "team_id": "yu75urhhxbhztiimoqpmrvmyzi",
  "updated_at": "2021-10-16T16:12:05.987433Z",
  "oldest_backup": "2021-10-06T05:00:15Z",
  "state": "ready",
  "cluster": {
    "id": "thatmhx5vndt5c6wijo7s6w45m",
    "cpu": 1,
    "disk_usage": {
      "disk_available_mb": 94935,
      "disk_total_size_mb": 100216,
      "disk_used_mb": 149
    },
    "cluster_id": null,
    "created_at": "2021-09-08T00:11:37.990338Z",
    "is_ha": false,
    "maintenance_window_start": null,
    "major_version": 13,
    "memory": 2,
    "name": "myCluster",
    "network_id": "63dkgt5warey7lhtbduwhqznii",
    "plan_id": "hobby-2",
    "postgres_version_id": "6ibnzig5avgutdgdzei2jwvvt4",
    "provider_id": "azure",
    "region_id": "eastus2",
    "replicas": [],
    "storage": 100,
    "team_id": "yu75urhhxbhztiimoqpmrvmyzi",
    "updated_at": "2021-10-16T16:12:05.987433Z",
    "oldest_backup": "2021-10-06T05:00:15Z",
    "state": "ready"
  }
}

Provisioning a cluster

Clusters can be provisioned against the API:

POST /clusters

There are a number of required and a few optional fields when creating your cluster:

  • Name - text [required]
  • Team - Unique team identifier [required]
  • Plan - Unique plan identifier [required]
  • Storage - Integer in MB [required]
  • Provider - Unique provider identifier [required]
  • PostgresVersionId - Either numeric version ie 14 or PostgresVersionId PostgresVersionId [required]
  • NetworkId - The ID of the network where the new cluster should be created. The cluster is created in its own new network if left empty. NetworkId
  • Region - Unique region identifier [required]
  • Version - Integer Postgres major version [required]
  • HA - Boolean to specify HA on or off (optional, default: false)

Refer to the Providers section for details on retrieving the unique identifiers for plans, providers, and regions.

An example request to create a cluster:

$ curl -X POST https://api.crunchybridge.com/clusters \
  -d '{
  "name": "",
  "team_id": "",
  "plan_id": "",
  "storage": 0,
  "provider_id": "",
  "postgres_version_id": null,
  "is_ha": false,
  "network_id": null,
  "region_id": "",
}' -H "Authorization: Bearer lf6b76vzhzc2hhudyacj4aqlgy"

Status codes:

  • 201 Created. A new cluster is provisioned.
  • 400 Bad Request. The request contains an invalid value, for example a decimal value for postgres_version_id.
  • 409 Conflict. The request specifies a non-unique name (i.e. a cluster that already exists).

Retrieving cluster credentials

Usable credentials for a cluster are retrieved through the separate roles endpoint. Their retrieval should be needed less frequently than standard cluster information, so hosting them separately reduces the likelihood that they’ll be accidentally leaked.

GET /clusters/{cluster_id}/roles/{role_id}

Currently, only the default role is supported, so all requests will look like:

GET /clusters/{cluster_id}/roles/default

The default role is the cluster’s superuser, which can be used to add other users by way of standard SQL.

{
  "name": "postgres",
  "password": "Yodtp6pRYzUsqNeHFIDVS3ViS266l5WeifCkdsvdzosQ1jTBMvKJKYF7h0tuMHd7",
  "uri": "postgres://postgres:Y[email protected]p.33ddusyv3fgkrf2bz67bxlkpwa.db.postgresbridge.com:5432/postgres"
}

Forking a cluster

Clusters can be forked at point in time against the API. Required fields are the same for provisioning a new cluster with the addition of one optional field:

  • Target Time - the target point in time, in RFC3339 format [optional, default: now()]

The target time should be a time between the oldest_backup and now(). The oldest backup time can be obtained from the cluster details listing API endpoint. Note: If not oldest backup is listed, then a backup currently doesn’t not exist for the cluster. This is common shortly after a cluster is first created.

POST /clusters/{cluster_id}/forks

An example POST to fork a cluster:

$ curl -X POST https://api.crunchybridge.com/clusters/rvf73a77ozfsvcttryebfrnlem/forks \
  -d '{
    "is_ha": false,
    "name": "staging-fork",
    "network_id": "lljj;da;jk",
    "plan_id": "hobby-2",
    "storage": 100,
    "provider_id": "aws",
    "region_id": "us-east-1",
    "storage": 2,
    "target_time": "2009-11-10T23:00:00Z"
  }' -H "Authorization: Bearer lf6b76vzhzc2hhudyacj4aqlgy"

is_ha boolean Whether the fork should be high availability, meaning that it has a secondary it can fail over to quickly in case the primary becomes unavailable.

  • Name A human-readable name for the fork. [required]
  • NetworkId The ID of the network where the new fork should be created. The cluster is created in its own new network if left empty.
  • PlanId The ID of the plan with which to create the fork. Determines instance, CPU, and memory. [required]
  • ProviderId The cloud provider in which to create the fork. [required]
  • RegionId The provider region in which to create the fork. [required]
  • Storage The amount of storage to make available to the fork in GB (gigabytes). if not provide will be the same as the cluster forking
  • TargetTime The time at which to fork from. Leave empty to fork at the current time.

Status codes:

  • 201 Created. A new fork is provisioned.
  • 400 Bad Request. The request contains an invalid value, or a backup currently does not exist.

Deleting a cluster

DELETE /clusters/{cluster_id}

curl -X DELETE https://api.crunchybridge.com/clusters/rvf73a77ozfsvcttryebfrnlem -H "Authorization: Bearer lf6b76vzhzc2hhudyacj4aqlgy"

Status codes:

  • 204 No Content. The cluster is successfully deleted.

Managing cluster firewall rules

The API allows you to create, update, delete, and retrieve a list of firewall rules.

Currently, you can create, update, or delete one firewall rule per call.

Retrieving firewall rules

Pass in the cluster ID as a path parameter to the following endpoint:

GET /clusters/{cluster_id}/firewall

Status code: 200 OK

{
  "firewall_rules": [
    {
      "id": "rwhpndhwrfdetco3wypdyuw4vm",
      "rule": "0.0.0.0/0"
    }
  ]
}

Firewall rules object

Attribute Type Description
id string Unique identifier for the firewall rule
rule string Specific IP address or valid CIDR block (IPv4, IPv6)

Creating a firewall rule

POST /clusters/{cluster_id}/firewall

curl -X POST https://api.crunchybridge.com/clusters/rvf73a77ozfsvcttryebfrnlem/firewall \
  -d '{"rule":"0.0.0.0/0"}' -H "Authorization: Bearer lf6b76vzhzc2hhudyacj4aqlgy"

Status codes:

  • 201 Created. A new firewall rule is added.
  • 400 Bad Request. The request body contains invalid values (e.g. invalid IP address).
  • 409 Conflict. There is a conflict with an existing firewall rule.

Getting a firewall rule

Get a specific firewall rule by sending cluster and firewall rule IDs:

GET /clusters/{cluster_id}/loggers/{firewall_rule_id}

Status code: 200 OK

Updating a firewall rule

Use the PUT method and pass in the cluster ID and firewall rule ID as path parameters to the following endpoint:

PUT /clusters/{cluster_id}/firewall/{firewall_rule_id}

curl -X PUT https://api.crunchybridge.com/clusters/rvf73a77ozfsvcttryebfrnlem/firewall/6ulthse7k5gm7kxz4cqwojagki \
  -d '{"rule":"172.27.153.74/24"}' -H "Authorization: Bearer lf6b76vzhzc2hhudyacj4aqlgy"

Status codes:

  • 204 No Content. The specified firewall rule is updated.
  • 400 Bad Request. The request body contains invalid values (e.g. invalid IP address).

Deleting a firewall rule

DELETE /clusters/{cluster_id}/firewall/{firewall_rule_id}

curl -X DELETE https://api.crunchybridge.com/clusters/rvf73a77ozfsvcttryebfrnlem/firewall/wgv6v6damvahth3wb76ee4awsu \
  -H "Authorization: Bearer lf6b76vzhzc2hhudyacj4aqlgy"

Status codes:

  • 204 No Content. The firewall rule is successfully removed.

Configuring logging integration

Logging integrations can also be configured per cluster via the API.

Retrieving log destinations

Pass in the cluster ID as a path parameter to the following endpoint:

GET /clusters/{cluster_id}/loggers

This will return the log destinations configured for the cluster:

Status code: 200 OK

{
  "loggers": [
    {
      "id": "s3q3zqzdr5fqbgya7xupxxpyva",
      "host": "syslog-a.logdna.com",
      "port": 6514,
      "template": "<${PRI}>1 ${ISODATE} ${HOST} ${PROGRAM} ${PID} ${MSGID} [[email protected] key=\\\"MY-INGESTION-KEY\\\"] $MSG\\n",
      "description": "My description"
    }
  ]
}

Loggers object

Attribute Type Description
id string Unique identifier for the logger
host string Endpoint hostname
port integer Port number
template string Format for log messages
description string Description

Adding a log destination

POST /clusters/{cluster_id}/loggers

The hostname, port, template, and description are required to create a log destination:

curl -X POST "https://api.crunchybridge.com/clusters/zceucbf5pjgkjbnk3uwcbmmkei/loggers" -d '{"host":"syslog-a.logdna.com", "port": 6514, "template":"<${PRI}>1 ${ISODATE} ${HOST} ${PROGRAM} ${PID} ${MSGID} [[email protected] key=\\\"MY-INGESTION-KEY\\\"] $MSG\n", "description":"My description" }' -H "Authorization: Bearer lf6b76vzhzc2hhudyacj4aqlgy"

Status codes:

  • 201 Created. A new log destination is added.
  • 400 Bad Request. The request body is missing a required field, or contains an invalid or incorrectly formatted value.

Getting a log destination

Get a specific log destination by sending cluster and logger IDs:

GET /clusters/{cluster_id}/loggers/{logger_id}

Status code: 200 OK

Editing a log destination

Pass in the cluster ID and logger ID to the following endpoint:

PUT /clusters/{cluster_id}/loggers/{logger_id}

Host, port, template, and description values are all required.

curl -X PUT "https://api.crunchybridge.com/clusters/zceucbf5pjgkjbnk3uwcbmmkei/loggers/s3q3zqzdr5fqbgya7xupxxpyva" -d '{"description":"My updated description", "host":"syslog-a.logdna.com", "port": 6514, "template":"<${PRI}>1 ${ISODATE} ${HOST} ${PROGRAM} ${PID} ${MSGID} [[email protected] key=\\\"MY-INGESTION-KEY\\\"] $MSG\n" }' -H "Authorization: Bearer lf6b76vzhzc2hhudyacj4aqlgy"

Status codes:

  • 204 No Content. The specified log destination is updated.
  • 400 Bad Request. The request body is missing a required field, or contains an invalid or incorrectly formatted value.

Deleting a log destination

DELETE /clusters/{cluster_id}/loggers/{logger_id}

curl -X DELETE "https://api.crunchybridge.com/clusters/zceucbf5pjgkjbnk3uwcbmmkei/loggers/s3q3zqzdr5fqbgya7xupxxpyva" -H "Authorization: Bearer lf6b76vzhzc2hhudyacj4aqlgy"

Status codes:

  • 204 No Content. The log destination is successfully removed.

Upgrading a cluster

The resize API can be used to change a cluster’s plan or the amount of storage it has.

Starting an Upgrade

Start an upgrade:

POST /clusters/{cluster_id}/upgrade

At least one of the following parameters is required:

  • PlanId (plan_id) - The new ID of the plan to change the cluster to..
  • Storage (storage) - New disk size in GB.
  • IsHa boolean - Changes the high availability status of the cluster.
  • MajorVersion number The Postgres major version number to upgrade the cluster to. Deprecated: Prefer sending a value to postgres_version_id instead which will also accept a major version number value.
  • PostgresVersionId enum see
  • Storage number The new storage size for the cluster in GB.
curl -X POST "https://api.crunchybridge.com/clusters/zceucbf5pjgkjbnk3uwcbmmkei/resize" -d '{"plan_id":"standard-64", "storage": 100}' -H "Authorization: Bearer lf6b76vzhzc2hhudyacj4aqlgy"

This will return the status of the upgrade:

Status codes:

  • 201 Created. Upgrade started.
  • 400 Bad Request. The request body is missing a required field, or contains an invalid or incorrectly formatted value.
{
  "flavor": "resize",
  "state": "resizing"
}

Upgrade object

Attribute Type Description
flavor string One of ha_change, major_version_upgrade, or resize
state string One of ready, scheduled, in_progress, or failing_over for a major version upgrade or resize.
One of enabling_ha, waiting_for_ha_standby or disabling_ha for an HA change.

Retrieving upgrade status

Get the current status of a upgrade:

GET /clusters/{cluster_id}/upgrade

curl -X GET "https://api.crunchybridge.com/clusters/zceucbf5pjgkjbnk3uwcbmmkei/upgrade" -H "Authorization: Bearer lf6b76vzhzc2hhudyacj4aqlgy"

Status code: 200 OK

Canceling an upgrade

Cancel an in progress resize:

DELETE /clusters/{cluster_id}/upgrade

curl -X DELETE "https://api.crunchybridge.com/clusters/zceucbf5pjgkjbnk3uwcbmmkei/upgrade" -H "Authorization: Bearer lf6b76vzhzc2hhudyacj4aqlgy"

Status codes:

  • 204 No Content. The upgrade was successfully canceled.

Cluster Status

Retrieve the status of a cluster

GET /clusters/{cluster_id}/status

curl  "https://api.crunchybridge.com/clusters/thatmhx5vndt5c6wijo7s6w45m" -H "Content-Type: application/json" -H "Authorization: Bearer cbat_jrjGhbhqEiFi4DTdqUypxQ5DHxOh-uU_EMYodKoOztg"

Status Object

{
  "disk_usage": {
    "disk_available_mb": 0,
    "disk_total_size_mb": 0,
    "disk_used_mb": 0
  },
  "oldest_backup_at": null,
  "ongoing_upgrade": {
    "operations": [
      {
        "flavor": null,
        "state": null
      }
    ]
  },
  "state": ""
}
Attribute Type Description
disk_usage Disk Usage Object
oldest_backup_at string The cluster’s oldest backup. May be null if no backup has occurred yet.
ongoing_upgrade Upgrade Object
state string The state of the cluster. One of creating, ready, restarting, or destroying.