# API Reference

# 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.crusoe.ai/api`](/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:

```sh
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"](../../identity-and-security/managing-api-keys.mdx).

#### 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:

- Sort 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:

```json
/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:

```sh
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

**py:**

```py
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.crusoe.ai/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))
```