# Authentication

> The API is protected by OpenID Connect. Machine to machine integrations exchange a client ID and secret for an access token.

API reference

The API is protected by **OpenID Connect**. Machine to machine integrations exchange a client ID and secret for an **access token**, and send that token as a bearer token on every request.

Token endpoint

https://auth.ebx.energy/oauth2/token

Client auth

client\_secret\_basic · client\_secret\_post

## Get a token

You need two things before your first call: credentials you create once, and a short-lived access token you exchange them for. **No request works without the token.**

1.  01
    
    ### Create client credentials
    
    In the Control Center under Organisation → Integrations, or via `POST /v1/integrations`, create a machine-to-machine integration and copy its client ID and secret. The secret is shown once; an integration holds two secrets at a time so it can be rotated without downtime.
    
    No Control Center access yet? Ask your EBX contact, or [request test access](https://ebx.energy) for instant test credentials.
    
2.  02
    
    ### Exchange them for an access token
    
    POST the `client_credentials` grant to the token endpoint. Both `client_secret_basic` (shown) and `client_secret_post` are accepted.
    
    Token request · cURL
    
    cURL:
    
    ```bash
    curl ·   · -X ·  POST  · "https://auth.ebx.energy/oauth2/token" ·  \
       · -u ·   · "$EBX_CLIENT_ID:$EBX_CLIENT_SECRET" ·  \
       · -H ·   · "Content-Type: application/x-www-form-urlencoded" ·  \
       · -d ·   · "grant_type=client_credentials"
    ```
    
    Python:
    
    ```python
    import ·  httpx
    
    res = httpx.post(
         · "https://auth.ebx.energy/oauth2/token" · , · 
        auth=(client_id · , ·  client_secret) · , · 
        data= · { · "grant_type" · : ·   · "client_credentials" · }, · 
    )
    token = res.json() · [ · "access_token" · ]
    ```
    
    TypeScript:
    
    ```typescript
    const ·  res =  · await ·  fetch( · "https://auth.ebx.energy/oauth2/token" · , ·   · { · 
       · method · : ·   · "POST" · , · 
       · headers · : ·   · { · 
        Authorization · : ·   · `Basic ${btoa(` · $ · { · clientId · }: · $ · { · clientSecret · } · `)}` · , · 
         · "Content-Type" · : ·   · "application/x-www-form-urlencoded" · , · 
       · }, · 
       · body · : ·   · new ·  URLSearchParams( · { ·  grant_type · : ·   · "client_credentials" ·   · } · ) · , · 
     · } · );
     · const ·   · { ·  access_token  · } ·  =  · await ·  res.json();
    ```
    
    Token response · 200
    
    ```json
    { · 
       · "access_token" · : ·   · "eyJhbGciOiJSUzI1NiIsImtpZCI6IjNiZTk..." · , · 
       · "token_type" · : ·   · "Bearer" · , · 
       · "expires_in" · : ·   · 3600 · , · 
       · "scope" · : ·   · "asset.read dispatch.read dispatch.write" · 
     · }
    ```
    
3.  03
    
    ### Cache it and reuse it
    
    The token is valid for **60 minutes**. Cache it and send it on every request until it expires, then exchange again. Don't request a token per call.
    

## Call the API

Send the access token in the `Authorization` header. A token only ever reaches the assets of its own organisation. Every endpoint in the reference states the scope it requires: a valid token missing that scope is rejected with `403`, a missing or expired token with `401`.

Authenticated request · cURL

cURL:

```bash
curl ·   · "https://api.ebx.energy/v1/users/me" ·  \
   · -H ·   · "Authorization: Bearer $EBX_TOKEN"
```

Python:

```python
import ·  httpx

res = httpx.get(
     · "https://api.ebx.energy/v1/users/me" · , · 
    headers= · { · "Authorization" · : ·  f · "Bearer {token}" · }, · 
)
print(res.json())
```

TypeScript:

```typescript
const ·  res =  · await ·  fetch( · "https://api.ebx.energy/v1/users/me" · , ·   · { · 
   · headers · : ·   · { ·  Authorization · : ·   · `Bearer ${token}` ·   · }, · 
 · } · );
 · const ·  me =  · await ·  res.json();
```

[Errors & status codes →](https://docs.ebx.energy/reference/errors.md)

## Scopes

Scopes are granted per integration in the Control Center and returned on the token. What each group unlocks:

Assets

asset.read · asset.write

Assets and their virtual segmentation, unavailability, power and energy limits, and backup-market defaults and bids.

Dispatch

dispatch.read · dispatch.write

Asset state and state history, and immediate or scheduled dispatch.

Markets

market.read · market.write

FCR and aFRR bids, the valid bid intervals and the auction results.

Restrictions

restrictions.review · restrictions.approve · restrictions.write\_direct

Reviewing and approving restriction requests. write\_direct applies a restriction without going through approval.

Alarms

alarm.read · alarm.write

Alarm history, active alarms and the rule catalogue; acknowledging and muting.

Onboarding

onboarding.read · onboarding.write

Onboarding workflows and their tasks: gates, DPL rows, RfI fields, documents and prequalification submission.

Reporting

report.read · invoice.read

Dispatch and performance reports, settlement over a range, and invoices.

Organisation

users.read · users.write · clients.read · clients.write

Users in your organisation and their scopes, and machine-to-machine integrations and their secrets.

Pools

pool.read · pool.write

Organisation pools and pool state. Beta.
