Skip to main content
If you build against Nomos with an AI agent (a coding assistant, an internal ops bot, an autonomous integration), you can hand it a skill that teaches it the API in one shot: the base URL, OAuth, versioning, pagination, filtering, error handling, and every endpoint grouped by the scope it needs. The agent then makes correct calls without you pasting docs into each prompt. The skill is scope-aware. It separates the read surface (every GET, available to a read:* token) from the write surface (mutating calls, which need write:*), so an agent holding a read-only key knows up front which endpoints it can use and treats the rest as unavailable.

Install the skill

The skill follows the Agent Skills format: a SKILL.md file with a name, a description, and a body the agent loads when the description matches the task.
1

Get the skill file

Copy the skill from the code block at the bottom of this page and save it as SKILL.md inside a folder named nomos-api.
2

Drop it where your agent looks for skills

mkdir -p ~/.claude/skills/nomos-api
# save the file as ~/.claude/skills/nomos-api/SKILL.md
For the Claude Agent SDK, point your agent at the same skills directory. For Cursor or another assistant, add the file to its rules or context directory.
3

Let the agent use it

The agent loads the skill when a task matches its description (building or debugging a Nomos integration). Ask it to call the API as usual; it now knows the endpoints and conventions.
Every page on this site can be sent straight to Claude, ChatGPT, or Cursor with the menu at the top right. The skill packages that knowledge into one reusable file instead.

What the skill knows, and what it defers

The skill carries the stable, conceptual knowledge: which endpoints exist, what they do, how auth and scopes work, and the shared conventions for pagination, filtering, and errors. It does not hard-code field-level request and response schemas, which change per version. Instead it points the agent at the live OpenAPI spec for the version it targets:
https://api.nomos.energy/openapi.2026-01-29.edison.json
So the skill is the map and the spec is the source of truth for exact fields. An agent that follows it fetches the spec before constructing a call.
The skill defaults guidance to the latest stable version, 2026-01-29.edison. Feed-in support and the renamed /usage endpoint require the 2026-05-27.curie preview; the skill calls out where version matters.

The skill

Save everything below as nomos-api/SKILL.md.
SKILL.md
---
name: nomos-api
description: >-
  Knowledge of the Nomos energy REST API (api.nomos.energy): base URL, OAuth
  authentication, versioning, pagination, filtering, error handling, and the
  full endpoint catalog for the German whitelabel energy platform. Use when
  building or debugging an integration that calls the Nomos API (subscriptions,
  leads, plans, customers, invoices, prices, consumption/usage, smart meter
  orders, grid fee reductions, market partners), or when an agent holds a Nomos
  OAuth token and needs to know which endpoints its scope (read:* vs write:*)
  allows.
---

# Nomos API

Nomos runs a whitelabel energy platform: partners sell electricity under their own brand while Nomos handles onboarding, supplier switching, metering, pricing, billing, and support. This skill describes the public REST API so an agent can call it correctly.

The API is REST over HTTPS only (plain HTTP is rejected). All requests share the base URL:

```
https://api.nomos.energy
```

Authoritative request and response schemas live in the OpenAPI spec, not in this file. Fetch the spec for exact field names, types, enums, and which fields are required:

```
https://api.nomos.energy/openapi.2026-01-29.edison.json
```

Swap the version segment to target another version (see Versioning). A browsable reference is at https://docs.nomos.energy.

## Authentication

The API uses OAuth 2.0. An integration holds a `client_id` and `client_secret` (created in the Nomos dashboard) and exchanges them for a short-lived bearer token.

Most integrations use the client credentials grant for server-to-server access against their own organization's data:

```bash
curl -X POST https://api.nomos.energy/oauth/token \
  -u "${CLIENT_ID}:${CLIENT_SECRET}" \
  -d grant_type=client_credentials
```

The response carries the token, its lifetime, a refresh token, and the granted scope:

```json
{
  "access_token": "eyJhbGciOiJI...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "21cc84a3ad98...",
  "scope": "read:* write:*"
}
```

Access tokens last 60 minutes. Cache the token and reuse it; when it expires, exchange the refresh token (`grant_type=refresh_token`, `refresh_token=...`) for a new pair rather than requesting a fresh token every call. Send the token on every request:

```bash
curl https://api.nomos.energy/subscriptions \
  -H "Authorization: Bearer ${ACCESS_TOKEN}"
```

If the integration acts on behalf of an end customer (for example a home energy manager reading one subscription's prices), use the authorization code grant with PKCE instead. The token usage and refresh model are identical.

## Scopes

This is the most important rule for an agent: what you can do is bounded by the token's scope. Two scopes exist today.

| Scope     | Grants                                                       |
| --------- | ------------------------------------------------------------ |
| `read:*`  | Every `GET` request across the API (the read surface below). |
| `write:*` | Every mutating request (`POST`, `PATCH`, `PUT`, `DELETE`).   |

The granted scope is in the `scope` field of the token response, space-delimited. Behavior to enforce:

- A token with only `read:*` can call every endpoint in the Read surface. Any call in the Write surface returns `403 FORBIDDEN`. Do not attempt writes with a read-only token; treat them as unavailable.
- A token with `read:* write:*` (the default, full access) can call everything.
- Scopes are fixed when the key is created and cannot be narrowed per request. To change a key's scope, a new key must be issued and rotated.

When you only need to read data (an ETL job, a BI sync, a monitoring agent), request a read-only key so a bug cannot mutate state.

## Versioning

The `X-API-Version` header selects the request and response shapes. Each Auth Client has a default version, used when the header is absent; new clients default to the latest stable release. Breaking changes ship only in a new version, so omitting the header keeps an integration stable. Build clients to ignore unrecognized response fields, since additive changes land in existing versions.

```bash
curl https://api.nomos.energy/subscriptions \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "X-API-Version: 2026-01-29.edison"
```

Every response echoes the version it was processed with in the `X-API-Version` header.

| Version             | Status                      |
| ------------------- | --------------------------- |
| `2026-05-27.curie`  | Preview (opt in explicitly) |
| `2026-01-29.edison` | Latest stable (default)     |
| `2025-12-16.batman` | Previous release            |
| `2025-12-01.chucky` | Initial stable release      |

Version-specific behavior worth knowing:

- Feed-in subscriptions (selling power back to the grid) require `2026-05-27.curie` or later. On earlier versions, leads, subscriptions, prices, and quotes for feed-in plans return `400 BAD_REQUEST`.
- The consumption endpoint was renamed in `2026-05-27.curie`: `GET /subscriptions/{id}/consumption` became `GET /subscriptions/{id}/usage`. On `curie` the old path returns `NOT_FOUND` pointing at the new one.

## Conventions

### Identifiers

IDs are prefixed by type: `cus_` (customer), `sub_` (subscription), `plan_` (plan), `lead_` (lead), `inv_` (invoice), `mp_` (market partner). Pass them verbatim in paths.

### Pagination

Every list endpoint returns the same envelope and uses cursor-based pagination, newest first by `created_at`.

```json
{
  "object": "list",
  "items": [],
  "has_more": true,
  "next_page": "eyJsYXN0X2NyZWF0ZWRfYXQiOi..."
}
```

- `limit`: page size, 1 to 100, default 10.
- `cursor`: pass the previous response's `next_page`. Omit on the first request.
- Stop when `has_more` is `false` (`next_page` is then `null`).
- Keep every other query parameter (filters, `limit`) identical across the walk, or the cursor is invalidated. A tampered cursor returns `400 BAD_REQUEST`.

### Filtering

List endpoints filter through bracket-notation query parameters: `filter[<field>][<operator>]=<value>`. Multiple filters combine with AND.

```bash
curl -G "https://api.nomos.energy/subscriptions" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  --data-urlencode "filter[status][eq]=active" \
  --data-urlencode "filter[created_at][gte]=2026-01-01T00:00:00Z"
```

Operators by field type:

- String: `eq`, `ne`, `in`, `is_null`, `contains`, `starts_with`, `ends_with` (the last three are case-insensitive).
- Number: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `is_null`.
- Date (ISO 8601 with timezone): `gte`, `lte`, `is_null`.
- Boolean: `eq`, `is_null`.
- Enum: `eq`, `ne`, `in`, `is_null`.

`in` takes a comma-separated list. An unknown field or a disallowed operator is silently ignored (it returns the unfiltered list), so a typo will not error. Malformed syntax or an invalid value returns `400 BAD_REQUEST` naming the parameter. The per-endpoint reference lists each filterable field and its allowed operators.

### Errors

Every error uses one envelope with standard HTTP status semantics:

```json
{
  "code": "BAD_REQUEST",
  "message": "invalid_type in 'customer.email': Required",
  "requestId": "37a04f8f-e791-491c-81e1-86cd304649bb",
  "docs": "https://docs.nomos.energy/api-references/errors/BAD_REQUEST"
}
```

Switch on `code`, not on the message. Log `requestId` for support.

| Status | Code                    | Meaning and handling                                                           |
| ------ | ----------------------- | ------------------------------------------------------------------------------ |
| 400    | `BAD_REQUEST`           | Validation failed or unparseable input. Fix the request; do not retry.         |
| 401    | `UNAUTHORIZED`          | Missing, invalid, or expired token. Refresh and retry.                         |
| 403    | `FORBIDDEN`             | Valid token without permission, often a scope mismatch (write with `read:*`).  |
| 404    | `NOT_FOUND`             | Resource does not exist or is outside your organization. Check the ID.         |
| 405    | `METHOD_NOT_ALLOWED`    | Wrong HTTP method for the endpoint.                                            |
| 409    | `CONFLICT`              | A unique value is already taken. Change it before retrying.                    |
| 422    | `UNPROCESSABLE_ENTITY`  | Well-formed request that breaks a business rule. Read `message`; do not retry. |
| 429    | `TOO_MANY_REQUESTS`     | Rate limited. Back off with exponential delay and jitter, then retry.          |
| 500    | `INTERNAL_SERVER_ERROR` | Nomos-side error. Retry with backoff; if it persists, contact support.         |

Retry only `429` and `5xx`. Never retry a `4xx` (except `429`) without changing the request.

## Read surface (requires `read:*`)

All endpoints below are `GET`. A read-only token can call every one of them.

### Plans

- `GET /plans` - list plans (the tariffs configured on your organization).
- `GET /plans/{id}` - retrieve a plan.
- `GET /plans/{id}/quote` - retrieve a quote for a plan. Prices include VAT. Feed-in quotes require `2026-05-27.curie`.

### Leads

- `GET /leads` - list leads (pre-filled checkout links you created).
- `GET /leads/{id}` - retrieve a lead.

### Subscriptions

- `GET /subscriptions` - list subscriptions.
- `GET /subscriptions/{id}` - retrieve a subscription.

### Customers

- `GET /customers` - list customers.
- `GET /customers/{id}` - retrieve a customer.

### Consumption

- `GET /subscriptions/{id}/consumption` - retrieve consumption data for a subscription. Renamed to `/usage` in `2026-05-27.curie`.
- `GET /subscriptions/{id}/usage` - retrieve usage data (`2026-05-27.curie` and later). Usage is electricity drawn from, or fed into, the grid; values are positive in both directions and the direction comes from the plan.
- `GET /subscriptions/{id}/meter_readings` - list meter readings for a subscription.

Smart meters: data becomes available from 4pm the following day, with preliminary values possibly replaced by final values up to the 8th working day of the next month. Analog meters: monthly values from customer or operator readings, with Nomos estimating at month-end until a reading arrives.

### Prices

- `GET /subscriptions/{id}/prices` - retrieve the price time series for a subscription to optimize consumption against. Prices include VAT. For feed-in subscriptions this is the per-kWh payout (EPEX day-ahead spot, no grid fees); feed-in requires `2026-05-27.curie`.

### Invoices

- `GET /subscriptions/{id}/invoices` - list a subscription's monthly invoices, including all line items (energy, grid fees, taxes). `type: "usage"` bills metered consumption; `type: "prepayment"` charges a fixed advance.
- `GET /invoices/{id}` - retrieve an invoice.
- `GET /invoices/{id}/file` - retrieve the invoice PDF.

### Smart meter orders

- `GET /meter-orders` - list smart meter orders.
- `GET /meter-orders/{id}` - retrieve a smart meter order.

### Grid fee reductions

- `GET /grid-fee-reductions` - list §14a EnWG grid fee reductions. Customer-scoped tokens see only their own.
- `GET /grid-fee-reductions/{id}` - retrieve a grid fee reduction.

### Market partners

- `GET /suppliers` - list German electricity retailers, used to populate a "previous supplier" dropdown in checkout. Filter by name with `filter[name][contains]=<query>`.
- `GET /suppliers/search` - deprecated; use `GET /suppliers` with the name filter instead.

### Events

- `GET /events/{id}` - retrieve an event by id (the payload referenced by a webhook).

## Write surface (requires `write:*`)

All endpoints below mutate state. A token without `write:*` gets `403 FORBIDDEN`. Before calling, fetch the endpoint's request schema from the OpenAPI spec; bodies are validated strictly.

### Subscriptions

- `POST /subscriptions` - create a subscription. Consumption plans support meter types, optional VAT ID, flexible start dates, previous-supplier cancellation, and product orders (smart meters, §14a). Feed-in plans require `2026-05-27.curie`, a present smart meter, a mandatory VAT ID for companies, future start dates, and no product orders.

### Leads

- `POST /leads` - create a lead: a secure, pre-filled checkout link returned in `link`, so a prospect finishes signup with only payment details. Feed-in leads require `2026-05-27.curie`.

### Consumption

- `POST /subscriptions/{id}/meter_readings` - submit a customer-reported analog meter reading for the subscription's active meter.

### Load forecasts

- `POST /load-forecasts` - transmit a load forecast for a subscription. Submit by 09:00 local time the previous day for the day-ahead auction, or at least 15 minutes before delivery for intraday. Data points must be strictly consecutive and cover full calendar days.

### Grid fee reductions

- `POST /grid-fee-reductions` - create a §14a EnWG grid fee reduction (consumption only, not feed-in). Active subscriptions create with `ordered` status and submit immediately; pending subscriptions create with `intended` and submit on confirmation.

### Smart meter orders

- `POST /meter-orders` - create a smart meter order for a subscription whose plan supports the smart-meter product. Not applicable to feed-in (a smart meter must already exist before feed-in signup).

## Working effectively against this API

- Read the granted `scope` from the token response and refuse to attempt out-of-scope calls; do not learn the scope by triggering `403`s.
- Pin `X-API-Version` explicitly so behavior does not shift when the default moves. Use `2026-01-29.edison` unless you need feed-in or `/usage`, which need `2026-05-27.curie`.
- Fetch the OpenAPI spec for the chosen version to get exact request bodies and response fields before constructing a call. Treat this file as the map, the spec as the schema.
- Paginate fully when a list endpoint is the source of truth; do not assume the first page is complete.
- On error, branch on `code`, retry only `429` and `5xx` with backoff, and surface `requestId` to the user when reporting a failure.