Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 117 additions & 1 deletion content/api/howto.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- integration
- oauth
- tokens
- service tokens
- developer guide
---

Expand All @@ -22,12 +23,24 @@

## Request the API

Clever Cloud's REST API offers two authentication mechanisms to meet different integration needs:
Clever Cloud's REST API offers three authentication mechanisms to meet different integration needs:

Check notice on line 26 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L26

[Google.Acronyms] Spell out 'REST', if it's unfamiliar to the audience.
Raw output
{"message": "[Google.Acronyms] Spell out 'REST', if it's unfamiliar to the audience.", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 26, "column": 16}}}, "severity": "INFO"}

* **API tokens** provide a straightforward way to authenticate requests on behalf of a specific user. These tokens operate similarly to passwords and should be handled with appropriate security measures. API tokens are ideal for personal scripts, CLI tools, and scenarios where you're accessing your own resources. Use them to request the API Bridge: https://api-bridge.clever-cloud.com

* **OAuth 1** is designed for third-party applications that need to access Clever Cloud resources on behalf of their users. This authentication flow allows applications to request permissions from users without requiring direct access to their credentials. OAuth 1 is recommended for public applications, services that integrate with multiple user accounts, or any scenario where user delegation is required.

* **Service tokens** are designed for machine-to-machine authentication scoped to an organisation. They carry a [role](/doc/account/organisations/#roles-and-privileges) and can optionally target a specific application or add-on. Based on the [Eclipse Biscuit](https://www.biscuitsec.org/) format, they can also be [attenuated locally](#inspect-and-attenuate) to derive more restricted tokens without any server-side call. Service tokens are ideal for CI/CD pipelines, automated deployments, and scenarios where actions should be performed on behalf of an organisation rather than a specific user. Use them to request the API directly: https://api.clever-cloud.com

Check notice on line 32 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L32

[Google.Passive] In general, use active voice instead of passive voice ('be attenuated').
Raw output
{"message": "[Google.Passive] In general, use active voice instead of passive voice ('be attenuated').", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 32, "column": 1}}}, "severity": "INFO"}

Check notice on line 32 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L32

[Google.Passive] In general, use active voice instead of passive voice ('are designed').
Raw output
{"message": "[Google.Passive] In general, use active voice instead of passive voice ('are designed').", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 32, "column": 22}}}, "severity": "INFO"}

Check notice on line 32 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L32

[Google.Passive] In general, use active voice instead of passive voice ('be performed').
Raw output
{"message": "[Google.Passive] In general, use active voice instead of passive voice ('be performed').", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 32, "column": 527}}}, "severity": "INFO"}

| | API tokens | OAuth 1 | Service tokens |
|---|---|---|---|
| **Scope** | User | User (delegated) | Organisation |
| **Resource restriction** | No | No | Optional (apps, add-ons) |
| **Offline attenuation** | No | No | Yes (Eclipse Biscuit) |
| **Max lifetime** | 1 year | 3 months | 1 year (default: 90 days) |
| **Role-based** | No | No (permission-based) | Yes (Admin, Manager, Developer, Accounting) |
| **API endpoint** | API Bridge only | Main API (v2, v4) | Main API (v2) |
| **Best for** | Personal scripts, CLI | Third-party apps | CI/CD, automation, M2M |

Comment on lines +39 to +43
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The OAuth 1 max lifetime is stated as "3 months", but the existing documentation states OAuth tokens last 1 year when created via Clever Tools and 3 months via Console/other integrations. Consider updating this row (or adding a footnote) to reflect that lifetime depends on how the OAuth token is created, to avoid contradicting the changelog entry.

Suggested change
| **Max lifetime** | 1 year | 3 months | 1 year (default: 90 days) |
| **Role-based** | No | No (permission-based) | Yes (Admin, Manager, Developer, Accounting) |
| **API endpoint** | API Bridge only | Main API (v2, v4) | Main API (v2) |
| **Best for** | Personal scripts, CLI | Third-party apps | CI/CD, automation, M2M |
| **Max lifetime** | 1 year | Depends on how you create it* | 1 year (default: 90 days) |
| **Role-based** | No | No (permission-based) | Yes (Admin, Manager, Developer, Accounting) |
| **API endpoint** | API Bridge only | Main API (v2, v4) | Main API (v2) |
| **Best for** | Personal scripts, CLI | Third-party apps | CI/CD, automation, M2M |
\* OAuth 1 tokens last up to 1 year when you create them with Clever Tools, and up to 3 months when you create them from the Console or other integrations.

Copilot uses AI. Check for mistakes.
Choose the authentication method that best aligns with your specific integration requirements and security considerations.

### API tokens
Expand Down Expand Up @@ -57,6 +70,109 @@
curl https://api-bridge.clever-cloud.com/v2/self -H "Authorization: Bearer [API_TOKEN]"
```

### Service tokens

Service tokens provide organisation-scoped authentication for automated systems, CI/CD pipelines, and service-to-service communication. Unlike API tokens, which are tied to a user account, service tokens act on behalf of an organisation with a specific [role](/doc/account/organisations/#roles-and-privileges).

Check notice on line 75 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L75

[Google.Passive] In general, use active voice instead of passive voice ('are tied').
Raw output
{"message": "[Google.Passive] In general, use active voice instead of passive voice ('are tied').", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 75, "column": 162}}}, "severity": "INFO"}

Each service token carries a role (Admin, Manager, Developer, or Accounting) that determines what actions it can perform. You can only create tokens with a role equal to or lower than your own. Tokens can also be scoped to a specific application or add-on within the organisation, further restricting their access. Note that the Developer role only grants access to application endpoints; accessing add-on endpoints requires at least the Manager role.

Check notice on line 77 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L77

[Google.Passive] In general, use active voice instead of passive voice ('be scoped').
Raw output
{"message": "[Google.Passive] In general, use active voice instead of passive voice ('be scoped').", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 77, "column": 211}}}, "severity": "INFO"}

Check notice on line 77 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L77

[Google.Semicolons] Use semicolons judiciously.
Raw output
{"message": "[Google.Semicolons] Use semicolons judiciously.", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 77, "column": 388}}}, "severity": "INFO"}

Service tokens have a configurable time-to-live (TTL) from 1 second up to 1 year (default: 90 days). The token value is only displayed once at creation time and cannot be retrieved afterwards. Store it securely.

Check notice on line 79 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L79

[Google.Acronyms] Spell out 'TTL', if it's unfamiliar to the audience.
Raw output
{"message": "[Google.Acronyms] Spell out 'TTL', if it's unfamiliar to the audience.", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 79, "column": 50}}}, "severity": "INFO"}

Check notice on line 79 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L79

[Google.Contractions] Use 'can't' instead of 'cannot'.
Raw output
{"message": "[Google.Contractions] Use 'can't' instead of 'cannot'.", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 79, "column": 162}}}, "severity": "INFO"}

Check notice on line 79 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L79

[Google.Passive] In general, use active voice instead of passive voice ('be retrieved').
Raw output
{"message": "[Google.Passive] In general, use active voice instead of passive voice ('be retrieved').", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 79, "column": 169}}}, "severity": "INFO"}

#### Create and manage with Clever Tools

[Clever Tools](https://github.com/CleverCloud/clever-tools) provides a `clever service-tokens` set of commands:

```bash
clever service-tokens create "CI pipeline" --org myOrg --role Developer
clever service-tokens create "Deploy bot" --org myOrg --role Manager --resources app_xxx,addon_yyy --expiration 30d
Comment thread
davlgd marked this conversation as resolved.
```

If you omit `--org`, the token is created in your personal space. If you omit `--role`, the CLI prompts you to select interactively.

Check notice on line 90 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L90

[Google.Passive] In general, use active voice instead of passive voice ('is created').
Raw output
{"message": "[Google.Passive] In general, use active voice instead of passive voice ('is created').", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 90, "column": 32}}}, "severity": "INFO"}
Comment thread
davlgd marked this conversation as resolved.

List, get details about, or revoke service tokens:

```bash
clever service-tokens list --org myOrg
clever service-tokens get <token-id-or-name> --org myOrg
clever service-tokens revoke <token-id-or-name> --org myOrg
```

#### Create and manage with the API

Service token endpoints are under `/v2/organisations/{id}/service-tokens`. See the [APIv2 Reference](/api/v2/) for the full specification. Here is a creation example using `clever curl`:

```bash
clever curl -X POST https://api.clever-cloud.com/v2/organisations/<ORG_ID>/service-tokens \
-H "Content-Type: application/json" \
-d '{
"name": "CI pipeline",
"description": "Token for automated deployments",
"role": "DEVELOPER",
"resources": ["app_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "addon_yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"],
"ttl_seconds": 2592000
}'
```

The `name` and `role` fields are required. The `role` value must be uppercase: `ADMIN`, `MANAGER`, `DEVELOPER`, or `ACCOUNTING`. `description`, `resources`, and `ttl_seconds` are optional (TTL defaults to 90 days). The `resources` field accepts an array of application IDs, add-on IDs, or real IDs to scope the token to.

Check notice on line 116 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L116

[Google.Passive] In general, use active voice instead of passive voice ('are required').
Raw output
{"message": "[Google.Passive] In general, use active voice instead of passive voice ('are required').", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 116, "column": 30}}}, "severity": "INFO"}

Check notice on line 116 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L116

[Google.Acronyms] Spell out 'TTL', if it's unfamiliar to the audience.
Raw output
{"message": "[Google.Acronyms] Spell out 'TTL', if it's unfamiliar to the audience.", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 116, "column": 190}}}, "severity": "INFO"}

The response contains a `token` field (the Biscuit token value, shown only once) and a `metadata` object with the token `id` (prefixed `token_`), `status`, `createdAt`, `expiredAt`, and other fields. Use `metadata.id` to manage the token afterwards (get details, revoke).

The list endpoint (`GET /v2/organisations/{id}/service-tokens`) supports `limit` and `offset` query parameters for pagination.

#### Use a service token

Service tokens authenticate directly against the main API (not the API Bridge). Pass the token as a Bearer token in the `Authorization` header:

```bash
curl https://api.clever-cloud.com/v2/organisations/<ORG_ID>/applications/<APP_ID> \
-H "Authorization: Bearer <SERVICE_TOKEN>"
```

If your token is not scoped to specific resources, you can also access collection endpoints such as `/v2/organisations/<ORG_ID>/applications`.

Check notice on line 131 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L131

[Google.Contractions] Use 'isn't' instead of 'is not'.
Raw output
{"message": "[Google.Contractions] Use 'isn't' instead of 'is not'.", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 131, "column": 15}}}, "severity": "INFO"}

> [!NOTE]
> Service tokens currently authenticate against v2 endpoints only. v4 endpoint support is not yet available.

Check notice on line 134 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L134

[Google.Contractions] Use 'isn't' instead of 'is not'.
Raw output
{"message": "[Google.Contractions] Use 'isn't' instead of 'is not'.", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 134, "column": 88}}}, "severity": "INFO"}
Comment thread
davlgd marked this conversation as resolved.

#### Inspect and attenuate

Service tokens are standard [Eclipse Biscuit](https://www.biscuitsec.org/) tokens that you can inspect and attenuate locally with the [`biscuit` CLI](https://github.com/biscuit-auth/biscuit-cli/releases).

To inspect a service token and see its embedded datalog facts (tenant, role, robot ID, expiration):

Check failure on line 140 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L140

[Vale.Spelling] Did you really mean 'datalog'?
Raw output
{"message": "[Vale.Spelling] Did you really mean 'datalog'?", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 140, "column": 49}}}, "severity": "ERROR"}

```bash
echo "$CC_SERVICE_TOKEN" | biscuit inspect -
```

Attenuation derives a more restricted token from an existing one. The operation is purely local and offline: it does not require any access to the Clever Cloud API or account. The attenuated token is cryptographically bound to the original and can only reduce permissions, never expand them.

Check notice on line 146 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L146

[Google.Contractions] Use 'doesn't' instead of 'does not'.
Raw output
{"message": "[Google.Contractions] Use 'doesn't' instead of 'does not'.", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 146, "column": 113}}}, "severity": "INFO"}

You can attenuate a token to **shorten its lifetime**. For example, an orchestrator holding a long-lived service token can derive a short-lived token before passing it to an external runner or a contractor who should not have access to the original credential:

Check notice on line 148 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L148

[Google.Contractions] Use 'shouldn't' instead of 'should not'.
Raw output
{"message": "[Google.Contractions] Use 'shouldn't' instead of 'should not'.", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 148, "column": 211}}}, "severity": "INFO"}

```bash
export RUNNER_TOKEN=$(echo "$CC_SERVICE_TOKEN" | biscuit attenuate - --add-ttl 45m --block "")
```

The resulting token expires after 45 minutes regardless of the original token's TTL. If the attenuated token is leaked, the exposure window is limited to its short lifetime.

Check notice on line 154 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L154

[Google.Acronyms] Spell out 'TTL', if it's unfamiliar to the audience.
Raw output
{"message": "[Google.Acronyms] Spell out 'TTL', if it's unfamiliar to the audience.", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 154, "column": 81}}}, "severity": "INFO"}

Check notice on line 154 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L154

[Google.Passive] In general, use active voice instead of passive voice ('is leaked').
Raw output
{"message": "[Google.Passive] In general, use active voice instead of passive voice ('is leaked').", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 154, "column": 110}}}, "severity": "INFO"}

Check notice on line 154 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L154

[Google.Passive] In general, use active voice instead of passive voice ('is limited').
Raw output
{"message": "[Google.Passive] In general, use active voice instead of passive voice ('is limited').", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 154, "column": 141}}}, "severity": "INFO"}

You can also attenuate a token to **restrict it to specific resources**. Starting from an unscoped service token, you can derive a token limited to a single application or add-on:

Check failure on line 156 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L156

[Vale.Spelling] Did you really mean 'unscoped'?
Raw output
{"message": "[Vale.Spelling] Did you really mean 'unscoped'?", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 156, "column": 91}}}, "severity": "ERROR"}

```bash
export APP_TOKEN=$(echo "$CC_SERVICE_TOKEN" | biscuit attenuate - --block 'check if resource("app_xxx")')
```

Or to a set of resources using `or`:

```bash
export SCOPED_TOKEN=$(echo "$CC_SERVICE_TOKEN" | biscuit attenuate - --block 'check if resource("app_xxx") or resource("addon_yyy")')
```

The attenuated token only works on endpoints targeting those resources and is rejected everywhere else. Both restrictions (TTL and resource scope) can be combined in a single attenuation step:

Check notice on line 168 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L168

[Google.Passive] In general, use active voice instead of passive voice ('is rejected').
Raw output
{"message": "[Google.Passive] In general, use active voice instead of passive voice ('is rejected').", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 168, "column": 76}}}, "severity": "INFO"}

Check notice on line 168 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L168

[Google.Acronyms] Spell out 'TTL', if it's unfamiliar to the audience.
Raw output
{"message": "[Google.Acronyms] Spell out 'TTL', if it's unfamiliar to the audience.", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 168, "column": 124}}}, "severity": "INFO"}

Check notice on line 168 in content/api/howto.md

View workflow job for this annotation

GitHub Actions / vale

[vale] content/api/howto.md#L168

[Google.Passive] In general, use active voice instead of passive voice ('be combined').
Raw output
{"message": "[Google.Passive] In general, use active voice instead of passive voice ('be combined').", "location": {"path": "content/api/howto.md", "range": {"start": {"line": 168, "column": 152}}}, "severity": "INFO"}

```bash
export TEMP_TOKEN=$(echo "$CC_SERVICE_TOKEN" | biscuit attenuate - --add-ttl 45m --block 'check if resource("app_xxx")')
```

To learn more about Eclipse Biscuit tokens, visit the [official documentation](https://doc.biscuitsec.org/) or try the [interactive playground](https://biscuit-demo.cleverapps.io/).

### clever curl

`clever curl` is a wrapper around `curl`, it supports the same arguments and handles the authentication automatically for you using the CLI account you're currently logged in with. It's a simple way to make requests to the Clever Cloud API if [Clever Tools](https://github.com/CleverCloud/clever-tools) are installed on your system.
Expand Down
5 changes: 5 additions & 0 deletions content/doc/account/organisations.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ keywords:
- collaboration
- permissions
- team
- service tokens
aliases:
- /account/organizations
- /doc/account/organizations
Expand Down Expand Up @@ -44,3 +45,7 @@ Edit organisation | βœ“ | βœ“ | | |
Delete organisation | βœ“ | | | |
Access Bills & Receive Invoices | βœ“ | | | βœ“ |
Access Repositories | βœ“ | βœ“ | βœ“ | |
Add / Remove service tokens | βœ“ | βœ“ | | |

> [!NOTE]
> When creating a service token, the caller can only assign a role equal to or lower than their own. For example, a Manager can create tokens with role Manager, Developer, or Accounting, but not Admin.
Loading