Skip to main content

API Reference

info

Crusoe Cloud is currently in private beta. If you do not currently have access, please request access to continue.

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.crusoecloud.com.

The current version while we are in private alpha is /v1alpha5.

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.crusoecloud.com/v1alpha5/... \
-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 there is no value (for example, no query params), then the line contains a single newline 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: /v1alpha5/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 /v1alpha5/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:

/v1alpha5/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("/v1alpha5/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.crusoecloud.com/v1alpha5/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/index.html
request_verb = "<INSERT_REQUEST_VERB>" # GET, PUT, POST, PATCH, DEL
query_params = "<INSERT_QUERY_PARAMS>" # if needed. empty otherwise.

# 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 = "/v1alpha5"

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.crusoecloud.com' + api_version + request_path, headers={'X-Crusoe-Timestamp': dt, 'Authorization': 'Bearer {0}:{1}:{2}'.format(signature_version, api_access_key, signature)})
data = response.text
mydata = json.loads(data)
print(json.dumps(mydata, indent=4))