Skip to main content

Public API

The Keebo public API provides programmatic access to Warehouse Optimization for Snowflake (KWO). It is a REST API secured with OAuth2 and hosted at:

https://kwo.api.keebo.ai/v1

The API covers Snowflake accounts, warehouses, and warehouse optimization settings. All requests require a bearer token obtained through the OAuth2 client credentials flow — see How Is API Authentication Configured? below.

How Is API Authentication Configured?

Before using the API, authenticate with the OAuth2 service to obtain an access token.

Run the following script:

# Set the client credentials provided by Keebo
export CLIENT_ID="your_client_id"
export CLIENT_SECRET="your_client_secret"

# Store the access token in an environment variable
export ACCESS_TOKEN=$(curl -s -X POST https://auth.keebo.ai/oauth/token \
-H "Content-Type: application/json" \
-d '{
"client_id": "'$CLIENT_ID'",
"client_secret": "'$CLIENT_SECRET'",
"audience": "https://kwo.api.keebo.ai/v1",
"grant_type": "client_credentials"
}' | jq -r '.access_token')

# Verify the token is set
echo $ACCESS_TOKEN
  • CLIENT_ID — Found on the General Settings page in the Keebo portal under "Public API."
  • CLIENT_SECRET — Found on the General Settings page in the Keebo portal under "Public API."
  • ACCESS_TOKEN — The output of the script. Pass this token as a Bearer token in the Authorization header of all API requests.

What Can Be Done With the API?

Accounts

Warehouses

Warehouse default optimization settings


Account Endpoints

How Is a Snowflake Account Added?

POST /accounts

Enrolls a Snowflake account in Keebo.

Request body (application/json):

FieldTypeRequiredDescription
hoststringYesSnowflake host URL (e.g. xy12345.us-east-2.aws.snowflakecomputing.com)
userstringYesSnowflake user (e.g. KEEBO_USER)
rolestringYesSnowflake role (e.g. KEEBO_ROLE)
databasestringYesKeebo metadata database (e.g. KEEBO_DATABASE)
schemastringYesKeebo metadata schema (e.g. KEEBO_SCHEMA)
credentials.keyPair.privateKeystringYesRSA private key in PEM format, base64-encoded
credentials.keyPair.privateKeyPasswordstringNoPassword for the private key, if encrypted

Responses:

StatusMeaning
201Account enrolled. Returns snowflakeAccountIdentifier.
400Bad request — invalid host, missing privileges, invalid role, or invalid credentials.
401Unauthorized.
409Account already enrolled.
500Internal server error.

Snowflake account identifier

The snowflakeAccountIdentifier value returned on success is used as the path parameter for all warehouse and rules endpoints. Retrieve it from Snowflake at any time by running:

SELECT CURRENT_ORGANIZATION_NAME() || '-' || CURRENT_ACCOUNT_NAME();

Warehouse Endpoints

All warehouse endpoints are scoped to a Snowflake account via the snowflakeAccountIdentifier path parameter.

How Are Warehouses Listed?

GET /accounts/{snowflakeAccountIdentifier}/warehouses

Returns a paginated list of warehouses registered with Keebo for the specified account.

Path parameters:

ParameterTypeDescription
snowflakeAccountIdentifierstringSnowflake account identifier (e.g. acme-marketing_test_account)

Query parameters:

ParameterTypeDefaultDescription
pageSizeinteger50Number of results per page (1–100)
pageNumberinteger0Zero-based page index

Responses:

StatusMeaning
200Returns an array of warehouse detail objects.
400Bad request — unknown account.
401Unauthorized.
500Internal server error.

How Is a Warehouse Added?

POST /accounts/{snowflakeAccountIdentifier}/warehouses

Registers a Snowflake warehouse with Keebo for the specified account.

Path parameters:

ParameterTypeDescription
snowflakeAccountIdentifierstringSnowflake account identifier

Request body (application/json):

FieldTypeRequiredDescription
namestringYesWarehouse name. If the name contains special characters, it must be quoted (e.g. "\"my_$pec1al warehouse\"")
labelsstring[]NoLabels to tag the warehouse (e.g. ["looker", "finance"]). Defaults to []
costSavingsConfig.aggressivenessstringNoCost savings aggressiveness level. Defaults to BALANCED. See Cost Savings Aggressiveness
costSavingsConfig.enabledbooleanNoWhether cost savings is enabled. Defaults to true

Responses:

StatusMeaning
200Warehouse registered. Returns a warehouse detail object.
400Bad request — missing permissions or warehouse limit reached.
401Unauthorized.
409Warehouse already registered.
500Internal server error.

How Are Warehouse Details Retrieved?

GET /accounts/{snowflakeAccountIdentifier}/warehouses/{warehouseName}

Returns details for a specific warehouse.

Path parameters:

ParameterTypeDescription
snowflakeAccountIdentifierstringSnowflake account identifier
warehouseNamestringWarehouse name

Responses:

StatusMeaning
200Returns a warehouse detail object.
400Bad request — unknown account or warehouse not found.
401Unauthorized.
500Internal server error.

How Is a Warehouse Updated?

PATCH /accounts/{snowflakeAccountIdentifier}/warehouses/{warehouseName}

Updates one or more warehouse settings. Partial updates are supported using the updateMask field — only fields listed in updateMask are applied; all others are ignored. If updateMask is omitted, all fields are required and a full update is performed.

Path parameters:

ParameterTypeDescription
snowflakeAccountIdentifierstringSnowflake account identifier
warehouseNamestringWarehouse name

Request body (application/json):

FieldTypeDescription
warehouse.namestringNew warehouse name
warehouse.sizestringWarehouse size (e.g. X-SMALL, MEDIUM)
warehouse.minClusterCountintegerMinimum number of clusters
warehouse.maxClusterCountintegerMaximum number of clusters
warehouse.autoSuspendintegerSeconds of inactivity before auto-suspend
warehouse.changeDetectionTypestringHow to handle size changes detected outside Keebo: ACCEPT_CHANGE_AS_DEFAULT or GENERATE_ERROR
warehouse.costSavingsConfig.aggressivenessstringCost savings aggressiveness level
updateMaskstringComma-separated list of fields to update (e.g. "size,minClusterCount,maxClusterCount")

Example — update size only:

{
"warehouse": {
"size": "X-SMALL"
},
"updateMask": "size"
}

Example — update cluster counts:

{
"warehouse": {
"minClusterCount": 3,
"maxClusterCount": 7
},
"updateMask": "minClusterCount,maxClusterCount"
}

Example — rename a warehouse:

{
"warehouse": {
"name": "new_warehouse_name"
},
"updateMask": "name"
}

Responses:

StatusMeaning
200Warehouse updated. Returns a warehouse detail object.
400Bad request.
401Unauthorized.
409Conflict.
500Internal server error.

How Is Cost Savings Enabled for a Warehouse?

POST /accounts/{snowflakeAccountIdentifier}/warehouses/{warehouseName}:enableCostSavings

Enables automated cost savings for a specific warehouse.

Path parameters:

ParameterTypeDescription
snowflakeAccountIdentifierstringSnowflake account identifier
warehouseNamestringWarehouse name

Responses:

StatusMeaning
200Cost savings enabled. No response body.
400Bad request — missing permissions, unknown account, auto-resume disabled, or active errors present.
401Unauthorized.
500Internal server error.

How Is Cost Savings Disabled for a Warehouse?

POST /accounts/{snowflakeAccountIdentifier}/warehouses/{warehouseName}:disableCostSavings

Disables automated cost savings for a specific warehouse.

Path parameters:

ParameterTypeDescription
snowflakeAccountIdentifierstringSnowflake account identifier
warehouseNamestringWarehouse name

Responses:

StatusMeaning
200Cost savings disabled. No response body.
400Bad request — missing permissions, unknown account, or active errors present.
401Unauthorized.
500Internal server error. If cost savings was successfully disabled but the warehouse could not be restored to its original settings, a DATA_LOSS response is returned with a RESTORE_SETTINGS_FAILURE reason and the expected settings values in the error details.

Warehouse Default Optimization Settings

Each warehouse has a set of default optimization settings that apply continuously across all hours and days. These settings serve as the baseline behavior. Time-specific rules — configured separately in the Keebo portal — override the defaults for the periods they cover, then revert to these defaults outside of those windows.

How Are Default Warehouse Optimization Settings Updated?

PATCH /accounts/{snowflakeAccountIdentifier}/warehouses/{warehouseName}/rules/default

Updates the default optimization settings for a warehouse. Partial updates are supported using updateMask — only the fields listed in updateMask are applied.

Path parameters:

ParameterTypeDescription
snowflakeAccountIdentifierstringSnowflake account identifier
warehouseNamestringWarehouse name

Request body (application/json):

FieldTypeDescription
rule.downsizing.enabledbooleanEnable or disable automated downsizing
rule.multiCluster.enabledbooleanEnable or disable multi-cluster optimization
rule.multiCluster.lowestMaxClusterCountintegerFloor for the maximum cluster count when multi-cluster optimization is active
updateMaskstringComma-separated list of fields to update (e.g. "downsizing,multiCluster")

Example:

{
"rule": {
"downsizing": { "enabled": true },
"multiCluster": { "enabled": true, "lowestMaxClusterCount": 2 }
},
"updateMask": "downsizing,multiCluster"
}

Responses:

StatusMeaning
200Settings updated. Returns the full default rule object.
400Bad request — unknown account, unknown warehouse, or unsupported feature (downsizing or multi-cluster not available for this warehouse).
500Internal server error.

Response body — the returned rule object:

FieldTypeDescription
namestringRule identifier. Always "default" for this endpoint.
createTimestringISO 8601 timestamp of when the rule was created.
defaultSizestringThe warehouse size this rule defaults to. See Warehouse Sizes.
defaultClusterCount.minintegerMinimum cluster count.
defaultClusterCount.maxintegerMaximum cluster count.
schedule.daysstring[]Days the rule applies. The default rule covers all seven days.
schedule.startobjectTime of day the rule starts. Empty object represents midnight (00:00:00).
schedule.durationstringDuration the rule applies, in seconds with s suffix (e.g. "86400s" for the full day).
downsizing.enabledbooleanWhether automated downsizing is active.
multiCluster.enabledbooleanWhether multi-cluster optimization is active.
multiCluster.lowestMaxClusterCountintegerFloor for the maximum cluster count when multi-cluster optimization is active.

Reference

Cost Savings Aggressiveness

The aggressiveness field controls how aggressively Keebo optimizes cost versus performance.

ValueDescription
BEST_PERFORMANCEPrioritizes query performance over cost savings
GOOD_PERFORMANCEFavors performance with moderate savings
BALANCEDDefault. Balances cost savings and performance equally
LOW_COSTFavors cost savings with acceptable performance impact
LOWEST_COSTMaximizes cost savings

Warehouse Details Object

Warehouse list, add, get, and update endpoints return a warehouse details object with the following fields:

FieldTypeDescription
namestringWarehouse name.
sizestringWarehouse size. See Warehouse Sizes.
minClusterCountintegerMinimum number of clusters.
maxClusterCountintegerMaximum number of clusters.
autoSuspendintegerSeconds of inactivity before the warehouse auto-suspends.
changeDetectionTypestringHow size changes detected outside Keebo are handled: ACCEPT_CHANGE_AS_DEFAULT or GENERATE_ERROR.
costSavingsConfig.aggressivenessstringCost savings aggressiveness level. See Cost Savings Aggressiveness.
costSavingsConfig.enabledbooleanWhether cost savings is enabled for this warehouse.

Warehouse Sizes

Valid values for the size field:

X-Small, Small, Medium, Large, X-Large, 2X-Large, 3X-Large, 4X-Large, 5X-Large, 6X-Large

Error Response Format

All 4xx and 5xx responses return a JSON error object:

{
"code": 3,
"grpc-code": "INVALID_ARGUMENT",
"message": "Human-readable error description",
"details": [
{
"reason": "REASON_CODE",
"metadata": {
"message": "Additional detail",
"invalidValue": "the value that caused the error"
}
}
]
}