Skip to main content

API Reference

Overview​

Crusoe Cloud's REST API can be used to programmatically control resources such as creating Virtual Machines or fetching information about your organization.

Base URL and version​

Crusoe Cloud's API is hosted at https://api.cloud.crusoe.ai.

The current version is /v1.

The full API reference is available at https://docs.crusoecloud.com/api.

Authentication​

In order to authenticate to Crusoe Cloud's API, you must sign all requests using the following algorithm.

To begin creating a signed request, you need several pieces of information about the request being made:

  • The version of the signature being generated
  • The API access key ID and secret key
  • The signature payload
  • A timestamp for approximately when the request was created and sent, to prevent replay attacks

Once you have this information, you can send requests with the X-Crusoe-Timestamp and Authorization headers to authenticate to the API:

curl https://api.cloud.crusoe.ai/v1/... \
-H "X-Crusoe-Timestamp: <RFC3339 timestamp>" \
-H "Authorization: Bearer <version:access_key_id:base64_encoded_signature>" \
...

Signature version​

The current version of the signature is 1.0.

Getting an API access key and secret key​

You can create an API access key and secret key by following the instructions in "Manage your API Keys".

Generating a signature​

The signature payload consists of the following information, separated by newline ("\n") characters:

http_path
canonicalized_query_params
http_verb
timestamp_header_value

If a component of the payload is empty (such as when you have no query params), its corresponding line in the signature payload should be an empty line (i.e., contain only a single newline \n character).

The payload is used to generate a SHA256 HMAC signature, using a raw-urlsafe-base64 decoded version of the secret key as the HMAC secret key. The resulting HMAC signature is then base64 encoded and concatenated to the version and access_key_id using the : character.

Canonical Query Parameters​

If query parameters are included in the request, you must canonicalize them into a single query string.

To create this string, you must:

  • Sorted parameters by name, lexicographically.
  • Separate all parameters with &.

If there are no query parameters, the canonical string is the newline character: \n.

For example if you have a request that includes: /v1/capacities?product_name=a100.8x&location=us-northcentral1-a the canonical query string would be: location=us-northcentral1-a&product_name=a100.8x\n.

Example​

As an example, imagine we have:

  • An API access key ID (gYFONy-6QKS1acgUEQrR4Q) and secret key (uZFGf918DmiBUwBWv8lnEg)
  • A GET request being made to /v1/capacities
  • Query params of product_name=a100.8x&location=us-northcentral1-a
  • At 2022-03-01T01:23:45+09:00

This would result in the following payload:

/v1/capacities
location=us-northcentral1-a&product_name=a100.8x
GET
2022-03-01T01:23:45+09:00

The payload is then put through: raw_url_base64_encode(hmac_sha256("/v1/capacities\nproduct_name=a100.8x&location=us-northcentral1-a\nGET\n2022-03-01T01:23:45+09:00\n", raw_url_base64_decode("uZFGf918DmiBUwBWv8lnEg"))).

The output is then concatenated together with 1.0:gYFONy-6QKS1acgUEQrR4Q (the version and access key ID) and placed in the authorization header:

curl https://api.cloud.crusoe.ai/v1/capacities \
-H "X-Crusoe-Timestamp: 2022-03-01T01:23:45+09:00" \
-H "Authorization: Bearer 1.0:gYFONy-6QKS1acgUEQrR4Q:ZWFmMzVjMWMwODExNDc0OGY2ZTRmMzI0Y2UxOTI3YWQ2OTcwNmIzZTM4YWJmYjRkYWVjODBlYWE4MzY2ZGZkYw"

Sample Code​

import hmac
import hashlib
import base64
import datetime
import requests
import json

api_access_key = "<INSERT_ACCESS_KEY>"
api_secret_key = "<INSERT_SECRET_KEY>"

request_path = "<INSERT_REQUEST_PATH>" # e.g., "/compute/images". see https://docs.crusoecloud.com/api
request_verb = "<INSERT_REQUEST_VERB>" # GET, PUT, POST, PATCH, DEL

# if there are query params, e.g. with requests.post(..., params=query_params, ...)
query_params = {
"param_1": "value_1",
"param_2": "value_2",
}
query_params = "&".join([f"{k}={v}" for k, v in sorted(query_params.items())])

# if there is a request body, e.g., with requests.post(..., json=body, ...)
body = {
"request_body_field_1": "value",
"request_body_field_2": "value",
}

signature_version = "1.0"
api_version = "/v1"

dt = str(datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0))
dt = dt.replace(" ", "T")

payload = api_version + request_path + "\n" + query_params + "\n" + request_verb + "\n{0}\n".format(dt)
decoded = base64.urlsafe_b64decode(api_secret_key + '=' * (-len(api_secret_key) % 4))
signature = base64.urlsafe_b64encode(hmac.new(decoded, msg = bytes(payload, 'ascii'), digestmod=hashlib.sha256).digest()).decode('ascii').rstrip("=")

# make sure this method matches your HTTP verb above
response = requests.get(
'https://api.cloud.crusoe.ai' + api_version + request_path,
headers={'X-Crusoe-Timestamp': dt, 'Authorization': 'Bearer {0}:{1}:{2}'.format(signature_version, api_access_key, signature)},
params=query_params,
# json=body,
)
data = response.text
mydata = json.loads(data)
print(json.dumps(mydata, indent=4))