# Crypture API

Base URL: `https://crypture.app`

Crypture stores the secrets (environment variables, API keys, connection strings) of a **project**.
A project has **environments** — by default `development` (`dev`), `staging` (`stg`) and `production` (`prd`) —
and each environment has one or more **configs**: the root config named after the shortcut (`prd`) plus
forks such as `prd_eu` or `dev_local`. A config is a flat set of `KEY=value` pairs.

The API is for servers, CI jobs and scripts that need to read (or write) the secrets of one project.

## Authentication

Every call needs a **project API token**, sent as a Bearer token:

```
Authorization: Bearer cry_...
```

A person creates the token in the dashboard: open the project → **API tokens** → **New token**, choose
which environments it may read (and optionally write), optionally an expiry date. The value is shown
**once**. A token only ever sees its own project, and only the environments it was granted.
Treat it like a password; revoke it from the same screen.

## Usage

### Load secrets into a process — the whole recipe

```bash
export CRYPTURE_TOKEN=cry_...
# write a .env file for your app / docker compose
curl -fsS -H "Authorization: Bearer $CRYPTURE_TOKEN" \
  "https://crypture.app/api/v1/secrets?environment=production&format=env" > .env

# or export straight into the current shell
set -a; source <(curl -fsS -H "Authorization: Bearer $CRYPTURE_TOKEN" \
  "https://crypture.app/api/v1/secrets?environment=prd&format=env"); set +a
```

`format=env` output is dotenv: values that need it are double-quoted with `\n`, `\"` and `\\` escapes,
so multi-line values (PEM keys) survive. Use `format=json` when a program reads the secrets itself.

### Write from CI

`POST /api/v1/secrets` with `{"environment":"staging","secrets":{"RELEASE":"1.4.2"}}` creates or updates the
given keys and leaves every other key alone. Needs a token with **write** on that environment.

## Errors and limits

Errors are JSON: `{"error": "human readable message", "code": "machine_code"}`.

| Status | code | Meaning |
|---|---|---|
| 400 | `missing_environment`, `invalid_secret`, `bad_request` | The request is incomplete or a key / value is invalid |
| 401 | `invalid_token` | Missing, unknown, disabled or expired token |
| 403 | `insufficient_permissions` | The token may not read / write that environment |
| 404 | `not_found` | No such environment / config / key in this project |
| 500 | `internal` | Our fault — retry later |

Keys must match `[A-Za-z_][A-Za-z0-9_.-]*` (max 256 chars); values are at most 64 KB. Every change made
with a token is recorded in the project's audit log under the token's name and can be rolled back from
the dashboard.

## Endpoints

### `GET /api/v1/secrets`

Read every secret of one config.

Returns the decrypted secrets of a config. `format=json` (default) returns an object; `format=env` and `format=yaml` return the file as text.

Auth: `Authorization: Bearer cry_...`

| Param | In | Type | Required | Description |
|---|---|---|---|---|
| `environment` | query | `string` | yes | Environment slug or shortcut: `production` or `prd`, `development` or `dev`, … |
| `config` | query | `string` | no | Config name, e.g. `prd_eu`. Default: the environment's root config (named after its shortcut, e.g. `prd`). |
| `format` | query | `"json" \| "env" \| "yaml"` | no | Default `json`. |
| `typed` | query | `"true"` | no | JSON only: return integers, decimals, booleans and JSON values as real JSON types instead of strings. |

Response:

```json
{
  "project": "Webshop",
  "environment": "production",
  "config": "prd",
  "secrets": { "DATABASE_URL": "postgres://…", "STRIPE_KEY": "sk_live_…", "WORKERS": "4" },
  "types": { "DATABASE_URL": "url", "STRIPE_KEY": "password", "WORKERS": "integer" }
}
```

```bash
curl -H "Authorization: Bearer $CRYPTURE_TOKEN" "https://crypture.app/api/v1/secrets?environment=production"
```

Errors: `400 missing_environment`, `401 invalid_token`, `403 insufficient_permissions`, `404 not_found`

### `POST /api/v1/secrets`

Create or update secrets in one config.

Upserts the given keys; other keys are untouched. Unchanged values are not rewritten (and not logged). With `"overwrite": false`, keys that already exist are skipped instead of updated.

Auth: `Authorization: Bearer cry_...`

| Param | In | Type | Required | Description |
|---|---|---|---|---|
| `environment` | body | `string` | yes | Environment slug or shortcut. |
| `config` | body | `string` | no | Config name; default the root config. |
| `secrets` | body | `object \| array` | yes | `{ "KEY": "value" }`, or `[{ "key": "KEY", "value": "value", "type": "url" }]` to set types. Types: text, password, email, url, uuid, date, datetime, integer, decimal, boolean, json, xml, yaml. |
| `overwrite` | body | `boolean` | no | Default `true`. |

Request body:

```json
{ "environment": "staging", "secrets": { "RELEASE": "1.4.2", "FEATURE_X": "true" } }
```

Response:

```json
{ "environment": "staging", "config": "stg", "created": ["FEATURE_X"], "updated": ["RELEASE"], "deleted": [], "unchanged": [], "skipped": [] }
```

```bash
curl -X POST -H "Authorization: Bearer $CRYPTURE_TOKEN" -H 'content-type: application/json' \
  -d '{"environment":"staging","secrets":{"RELEASE":"1.4.2"}}' "https://crypture.app/api/v1/secrets"
```

Errors: `400 invalid_secret`, `401 invalid_token`, `403 insufficient_permissions`, `404 not_found`

### `DELETE /api/v1/secrets`

Delete one secret.

Auth: `Authorization: Bearer cry_...`

| Param | In | Type | Required | Description |
|---|---|---|---|---|
| `environment` | query | `string` | yes | Environment slug or shortcut: `production` or `prd`, `development` or `dev`, … |
| `config` | query | `string` | no | Config name, e.g. `prd_eu`. Default: the environment's root config (named after its shortcut, e.g. `prd`). |
| `key` | query | `string` | yes | The key to delete. |

Response:

```json
{ "environment": "staging", "config": "stg", "created": [], "updated": [], "deleted": ["OLD_FLAG"], "unchanged": [], "skipped": [] }
```

```bash
curl -X DELETE -H "Authorization: Bearer $CRYPTURE_TOKEN" "https://crypture.app/api/v1/secrets?environment=stg&key=OLD_FLAG"
```

Errors: `401 invalid_token`, `403 insufficient_permissions`, `404 not_found`

### `GET /api/v1/environments`

List the environments and configs this token can read.

Auth: `Authorization: Bearer cry_...`

Response:

```json
{
  "project": "Webshop",
  "token": "ci-deploy",
  "environments": [
    { "slug": "staging", "shortcut": "stg", "name": "Staging", "access": "read_write", "configs": ["stg"] },
    { "slug": "production", "shortcut": "prd", "name": "Production", "access": "read", "configs": ["prd", "prd_eu"] }
  ]
}
```

```bash
curl -H "Authorization: Bearer $CRYPTURE_TOKEN" "https://crypture.app/api/v1/environments"
```

Errors: `401 invalid_token`

Human-readable version of this document: https://crypture.app/docs/api
