# Create a custom tariff

Create a custom tariff from a weekly pattern of rates, optionally assigning it to a user in the same request.
Use this when a user's tariff is not in the public list returned by `GET /tariffs`. See [Creating custom tariffs](/docs/howto/custom_tariffs) for a walkthrough, and use the [tariff builder](/tools/tariff-builder) to build and check `rate_periods` visually.
**Ownership and privacy.** With the Client Credentials grant, the tariff is owned by the organisation linked to your application and is private to it: other organisations' applications get `404` for it, and links to it from other resources render as `null`. ev.energy's own apps show it only to users it is assigned to. An application that acts for a user (Authorization Code grant) creates a tariff owned by that user instead, even when the application is linked to an organisation. A tariff owned by a user, including one created in the ev.energy app, is visible only to that user, to users it is assigned to, and to organisations whose users created it or have it as their import or export tariff. A Client Credentials application not linked to an organisation cannot create tariffs and gets `403`. Custom tariffs are never added to the public tariff list.
**Rates.** `rate_periods` describes a typical week for each month. Every combination of month (1–12) and ISO weekday (1–7) must be covered by exactly one period, and each period's `rates` must fill the whole day on half-hour boundaries. `public_holiday_rates`, if sent, replaces the normal rates on the public holidays of the given country.
**Defaults.** `region`, `currency` and `timezone_name` default to the values for `user` when it is sent. `supplier` defaults to a generic "My supplier". If a value is missing and cannot be defaulted, the request fails with `422`.
**Assignment.** When `user` is set, the tariff becomes that user's import tariff (`default_location.tariff`) in the same transaction. Sending `user` also requires the `user:write` scope, the same as assigning a tariff with `PATCH /users/{user_id}`; without it the request fails with `403`. If any part of the request fails, nothing is written.
Prices for the next 52 weeks are generated when the tariff is created, and are available from `GET /tariffs/{tariff_id}/prices`.

Endpoint: POST /tariffs
Version: 2.0
Security: oauth2

## Security:

  - `oauth2` (unknown)
    oauth2 scopes: tariff:write

## Header parameters:

  - `EvEnergy-Version` (number)
    Specify the version of this endpoint to use.

## Request fields (application/json):

  - `name` (string, required)
    The tariff's name as the user knows it.
    Example: EV Saver

  - `supplier` (string)
    URL of the energy supplier, from `GET /suppliers`. Defaults to a generic "My supplier".
    Example: https://api.ev.energy/v2/suppliers/supl01HN2NJ9NMRZBXT1H6FT9N7735

  - `supplier_tariff_id` (string | null)
    Your or the supplier's own reference for this tariff. Stored for reference only.
    Example: EVS-2026-10

  - `region` (string)
    URL of a public reference region, or of a region your organisation created if your application is linked to one. Applications linked to an organisation can list both with `GET /regions`. Defaults to the region of `user`. Required if `user` is not sent.
    Example: https://api.ev.energy/v2/regions/regn01JCK1HPNAANB8WN253G27SFPC

  - `currency` (string)
    ISO 4217 currency code the rates are priced in. Defaults to the currency of `user`. Required if `user` is not sent.
    Example: GBP

  - `timezone_name` (string)
    IANA timezone the rate times are in, from `GET /timezones`. Defaults to the timezone of `user`. Required if `user` is not sent. The timezone's offset from UTC must always be a whole or half hour, because prices start on UTC half hours; timezones such as `Asia/Kathmandu`, `Australia/Eucla` and `Pacific/Chatham` are rejected with `422`.
    Example: Europe/London

  - `user` (string)
    URL of a user you can access. If sent, the new tariff becomes this user's import tariff in the same transaction.
    Example: https://api.ev.energy/v2/users/user01HN2NJ9NMRZBXT1H6FT9N7735

  - `rate_periods` (array, required)
    The weekly rate pattern for each month. Every combination of month and ISO weekday must be covered by exactly one period.

  - `rate_periods.months` (array, required)
    Months this period applies to, where 1 is January and 12 is December.
    Example: [1,2,3,4,5,6,7,8,9,10,11,12]

  - `rate_periods.iso_weekdays` (array, required)
    ISO 8601 weekdays this period applies to, where 1 is Monday and 7 is Sunday.
    Example: [1,2,3,4,5]

  - `rate_periods.rates` (array, required)
    The rates for one day. Together they must cover all 24 hours with no gaps or overlaps.

  - `rate_periods.rates.start_time` (string, required)
    Local start time as `HH:MM`, on the hour or half hour.
    Example: 00:00

  - `rate_periods.rates.end_time` (string, required)
    Local end time as `HH:MM`, on the hour or half hour.
    Example: 07:00

  - `rate_periods.rates.price_minor_units_per_kwh` (string, required)
    Price per kWh in the smallest unit of the tariff's currency (for example pence for GBP or cents for USD), as a decimal string with up to 6 decimal places. Negative prices are allowed.
    Example: 7.5

  - `rate_periods.rates.is_off_peak` (boolean)
    Whether this rate is an off-peak rate. Off-peak rates are labelled as such in charging summaries and in the app.

  - `public_holiday_rates` (object)
    The daily rates that replace the normal rates on public holidays. For tariffs created or repriced through the API, when a holiday falls on a weekend and the country moves it to a weekday (for example UK bank holidays), only the weekday it moves to uses these rates.

  - `public_holiday_rates.country` (string, required)
    ISO 3166-1 alpha-2 country code whose public holidays apply.
    Example: GB

  - `public_holiday_rates.subdivision` (string | null)
    Optional country subdivision whose public holidays apply, for example `ENG` (England) for GB or `NY` for US. Omit or send `null` to use only the national holidays.
    Example: ENG

  - `public_holiday_rates.rates` (array, required)
    The rates for a public holiday. Together they must cover all 24 hours with no gaps or overlaps.

## Request examples:

  - `GB dual rate with weekend and holiday rates` (unknown)

## Response 201:

  - `201` (unknown)
    Tariff created. The response is the tariff as returned by `GET /tariffs/{tariff_id}`.

## Response 201 fields (application/json):

  - `current_price` (integer | null)
    The price of the tariff at the current time, given in the smallest unit of the currency of the tariff. For example, 10 means 10 pence. `null` for licensed tariffs without the tariff:prices:read scope.
    Example: 10

  - `supplier_tariff_id` (string | null)
    The supplier's own identifier for this tariff, if one was provided.
    Example: ABC-1

  - `prices` (any)
    Link to prices endpoint by default. When expanded with ?expand=prices, returns all of the tariff's prices, newest first. Use `GET /tariffs/{tariff_id}/prices` to page through a time range. Price amounts on licensed tariffs are `null` without the tariff:prices:read scope.

  - `prices.started_at` (string, required)
    When this price interval began (ISO 8601 datetime).
    Example: 2024-01-15T10:00:00Z

  - `prices.interval_seconds` (integer, required)
    The duration of this price interval in seconds.
    Example: 1800

  - `prices.price_minor_units` (integer | null, required)
    The price in minor currency units (e.g., pence for GBP), truncated toward zero to a whole unit (e.g., 7.5p is given as `7`). Use `price_minor_units_decimal` for the exact price. Whether it includes VAT is given by the tariff's `prices_include_vat`. `null` for licensed tariffs without the tariff:prices:read scope.
    Example: 24

  - `prices.price_excluding_vat_minor_units` (integer | null, required)
    The price excluding VAT in minor currency units (e.g., pence for GBP), truncated toward zero to a whole unit. Use `price_excluding_vat_minor_units_decimal` for the exact price. `null` if the tariff's price source does not provide it, or for licensed tariffs without the tariff:prices:read scope.
    Example: 23

  - `prices.price_minor_units_decimal` (string | null, required)
    The exact price in minor currency units (e.g., pence for GBP) as a decimal string, without trailing zeros or exponent notation. Whether it includes VAT is given by the tariff's `prices_include_vat`. `null` for licensed tariffs without the tariff:prices:read scope.
    Example: 24.57

  - `prices.price_excluding_vat_minor_units_decimal` (string | null, required)
    The exact price excluding VAT in minor currency units (e.g., pence for GBP) as a decimal string, without trailing zeros or exponent notation. `null` if the tariff's price source does not provide it, or for licensed tariffs without the tariff:prices:read scope.
    Example: 23.4

  - `prices.is_internal_forecast` (boolean, required)
    `true` when price is forecasted using past data and tariff type. Generally, forecast data is only used as a temporary measure for creating schedules in advance while real price data has not been published yet.
    Example: false

  - `rate_periods` (array | null)
    The weekly rate pattern in force today, in the tariff's timezone, in the same format used by `POST /tariffs`. A repricing scheduled with `PATCH /tariffs/{tariff_id}` is not shown here until its `effective_from` date.
`null` when the tariff's rates cannot be described this way, for example tariffs with dynamic prices or with rates for specific dates. Use `GET /tariffs/{tariff_id}/prices` for the actual prices of any tariff. `null` for licensed tariffs without the tariff:prices:read scope.

  - `rate_periods.months` (array, required)
    Months this period applies to, where 1 is January and 12 is December.
    Example: [1,2,3,4,5,6,7,8,9,10,11,12]

  - `rate_periods.iso_weekdays` (array, required)
    ISO 8601 weekdays this period applies to, where 1 is Monday and 7 is Sunday.
    Example: [1,2,3,4,5]

  - `rate_periods.rates` (array, required)
    The rates for one day. Together they must cover all 24 hours with no gaps or overlaps.

  - `rate_periods.rates.start_time` (string, required)
    Local start time as `HH:MM`, on the hour or half hour.
    Example: 00:00

  - `rate_periods.rates.end_time` (string, required)
    Local end time as `HH:MM`, on the hour or half hour.
    Example: 07:00

  - `rate_periods.rates.price_minor_units_per_kwh` (string, required)
    Price per kWh in the smallest unit of the tariff's currency (for example pence for GBP or cents for USD), as a decimal string with up to 6 decimal places. Negative prices are allowed.
    Example: 7.5

  - `rate_periods.rates.is_off_peak` (boolean)
    Whether this rate is an off-peak rate. Off-peak rates are labelled as such in charging summaries and in the app.

  - `public_holiday_rates` (any)
    The rates that replace the normal rates on public holidays, as in force today. `null` if the tariff has no holiday rates, or if `rate_periods` is `null`.

  - `public_holiday_rates.country` (string, required)
    ISO 3166-1 alpha-2 country code whose public holidays apply.
    Example: GB

  - `public_holiday_rates.subdivision` (string | null)
    Optional country subdivision whose public holidays apply, for example `ENG` (England) for GB or `NY` for US. Omit or send `null` to use only the national holidays.
    Example: ENG

  - `public_holiday_rates.rates` (array, required)
    The rates for a public holiday. Together they must cover all 24 hours with no gaps or overlaps.

## Response 201 headers (application/json):

  - `EvEnergy-Version` (number)
    Indicates the version of the API that generated this response. If EvEnergy-Version was not specified in the request, this will be your OAuth application's default version.
    Enum: "2"

  - `X-RateLimit-Limit` (number)
    The maximum number of requests that can be made to this endpoint per hour. Defaults to 1000 but may vary per client.

  - `X-RateLimit-Remaining` (number)
    The number of requests remaining until this client's rate limit is reached.

  - `RetryAfter` (number)
    The number of seconds until this client's requests will not be rate limited.

## Response 400:

  - `400` (unknown)
    A problem with the request's parameters prevented it being fulfilled.

## Response 400 fields (application/problem+json):

  - `type` (string)
    Example: https://api.ev.energy/v2/problems/example-problem/

  - `status` (number)
    Example: 400

  - `title` (string, required)
    Example: Short description

  - `detail` (string, required)
    Example: Long, more specific description.

  - `instance` (string)
    Example: https://api.ev.energy/v2/users/user01HN2P75GBNFRJPCZJXEFVXH5E

  - `notification` (object)
    Something that the user should be informed about.

  - `notification.id` (string, required)
    Unique identifier for the Notification
    Example: notf67O36PLTFDB57M0E5L33JZLGM0

  - `notification.url` (string, required)
    Example: https://api.ev.energy/notifications/notf67O36PLTFDB57M0E5L33JZLGM0

  - `notification.message_id` (string, required)
    Internal identifier for this notification type. E.g. 'ERR0023'

  - `notification.category` (string, required)
    Category of this notification type
    Enum: "ACTIONABLE", "SERVICE", "RETRY", "MARKETING", "INTERNAL"

  - `notification.event_time` (string, required)
    The timestamp of the event described by this notification

  - `notification.short_text_title` (string, required)
    Short title for the notification

  - `notification.short_text_body` (string, required)
    Short description of the event being notified

  - `notification.detail_page_title` (string, required)
    Title of a help page giving more information about this notification

  - `notification.detail_page_body` (string, required)
    Text of a help page giving more information about this notification

  - `notification.external_link` (string | null, required)
    URL of a web page giving further information about this notification

  - `notification.external_button_label` (string, required)
    Text to be displayed on a button leading to the external_link location

  - `notification.read_at` (string)
    When the user examined the contents of this notification

  - `notification.resolved_at` (string)
    When the problem associated with this notification was resolved

## Response 400 headers (application/problem+json):

  - `EvEnergy-Version` (number)
    Indicates the version of the API that generated this response. If EvEnergy-Version was not specified in the request, this will be your OAuth application's default version.
    Enum: "2"

  - `X-RateLimit-Limit` (number)
    The maximum number of requests that can be made to this endpoint per hour. Defaults to 1000 but may vary per client.

  - `X-RateLimit-Remaining` (number)
    The number of requests remaining until this client's rate limit is reached.

  - `RetryAfter` (number)
    The number of seconds until this client's requests will not be rate limited.

## Response 401:

  - `401` (unknown)
    You need to authorise requests to access this resource.

## Response 401 fields (application/problem+json):

  - `status` (number)
    Example: 401

  - `title` (string, required)
    Example: Unauthorized

  - `detail` (string, required)
    Example: Authentication credentials were not provided.

## Response 401 headers (application/problem+json):

  - `EvEnergy-Version` (number)
    Indicates the version of the API that generated this response. If EvEnergy-Version was not specified in the request, this will be your OAuth application's default version.
    Enum: "2"

  - `X-RateLimit-Limit` (number)
    The maximum number of requests that can be made to this endpoint per hour. Defaults to 1000 but may vary per client.

  - `X-RateLimit-Remaining` (number)
    The number of requests remaining until this client's rate limit is reached.

  - `RetryAfter` (number)
    The number of seconds until this client's requests will not be rate limited.

## Response 403:

  - `403` (unknown)
    You do not have permission to perform this action.

## Response 403 fields (application/problem+json):

  - `status` (number)
    Example: 403

  - `title` (string, required)
    Example: Forbidden

  - `detail` (string, required)
    Example: You do not have permission to perform this action.

## Response 403 headers (application/problem+json):

  - `EvEnergy-Version` (number)
    Indicates the version of the API that generated this response. If EvEnergy-Version was not specified in the request, this will be your OAuth application's default version.
    Enum: "2"

  - `X-RateLimit-Limit` (number)
    The maximum number of requests that can be made to this endpoint per hour. Defaults to 1000 but may vary per client.

  - `X-RateLimit-Remaining` (number)
    The number of requests remaining until this client's rate limit is reached.

  - `RetryAfter` (number)
    The number of seconds until this client's requests will not be rate limited.

## Response 406:

  - `406` (unknown)
    Could not satisfy the request Accept header.

## Response 406 fields (application/problem+json):

  - `status` (number)
    Example: 406

  - `title` (string, required)
    Example: Not Acceptable

  - `detail` (string, required)
    Example: Could not satisfy the request Accept header.

## Response 406 headers (application/problem+json):

  - `EvEnergy-Version` (number)
    Indicates the version of the API that generated this response. If EvEnergy-Version was not specified in the request, this will be your OAuth application's default version.
    Enum: "2"

  - `X-RateLimit-Limit` (number)
    The maximum number of requests that can be made to this endpoint per hour. Defaults to 1000 but may vary per client.

  - `X-RateLimit-Remaining` (number)
    The number of requests remaining until this client's rate limit is reached.

  - `RetryAfter` (number)
    The number of seconds until this client's requests will not be rate limited.

## Response 422:

  - `422` (unknown)
    The request body failed validation (problem type `validation-failed-tariff`). Each invalid field is listed under `field_errors`. The rules are:
- Every combination of month (1–12) and ISO weekday (1–7) must be covered by exactly one entry in
`rate_periods`
.
- Each day's
`rates`
 must cover all 24 hours with no gaps or overlaps, and every time must be on the hour or half hour. A single rate whose
`start_time`
 equals its
`end_time`
 is a flat rate for the whole day.
- `public_holiday_rates.country`
 and
`subdivision`
 must be a known country and subdivision.
- `region`
,
`supplier`
 and
`user`
 must exist and be visible to you.
- `region`
,
`currency`
 and
`timezone_name`
 are required when
`user`
 is not sent.
- `timezone_name`
 must be a timezone whose offset from UTC is always a whole or half hour.
- On update,
`effective_from`
 must be strictly after today and no more than two years after today in the tariff's timezone, and must be sent together with
`rate_periods`
.

## Response 422 fields (application/problem+json):

  - `type` (string)
    Example: https://api.ev.energy/v2/problems/example-problem/

  - `status` (number)
    Example: 400

  - `title` (string, required)
    Example: Short description

  - `detail` (string, required)
    Example: Long, more specific description.

  - `instance` (string)
    Example: https://api.ev.energy/v2/users/user01HN2P75GBNFRJPCZJXEFVXH5E

  - `notification` (object)
    Something that the user should be informed about.

  - `notification.id` (string, required)
    Unique identifier for the Notification
    Example: notf67O36PLTFDB57M0E5L33JZLGM0

  - `notification.url` (string, required)
    Example: https://api.ev.energy/notifications/notf67O36PLTFDB57M0E5L33JZLGM0

  - `notification.message_id` (string, required)
    Internal identifier for this notification type. E.g. 'ERR0023'

  - `notification.category` (string, required)
    Category of this notification type
    Enum: "ACTIONABLE", "SERVICE", "RETRY", "MARKETING", "INTERNAL"

  - `notification.event_time` (string, required)
    The timestamp of the event described by this notification

  - `notification.short_text_title` (string, required)
    Short title for the notification

  - `notification.short_text_body` (string, required)
    Short description of the event being notified

  - `notification.detail_page_title` (string, required)
    Title of a help page giving more information about this notification

  - `notification.detail_page_body` (string, required)
    Text of a help page giving more information about this notification

  - `notification.external_link` (string | null, required)
    URL of a web page giving further information about this notification

  - `notification.external_button_label` (string, required)
    Text to be displayed on a button leading to the external_link location

  - `notification.read_at` (string)
    When the user examined the contents of this notification

  - `notification.resolved_at` (string)
    When the problem associated with this notification was resolved

## Response 422 headers (application/problem+json):

  - `EvEnergy-Version` (number)
    Indicates the version of the API that generated this response. If EvEnergy-Version was not specified in the request, this will be your OAuth application's default version.
    Enum: "2"

  - `X-RateLimit-Limit` (number)
    The maximum number of requests that can be made to this endpoint per hour. Defaults to 1000 but may vary per client.

  - `X-RateLimit-Remaining` (number)
    The number of requests remaining until this client's rate limit is reached.

## Response 429:

  - `429` (unknown)
    The client has exceeded its rate limit.

## Response 429 fields (application/problem+json):

  - `type` (string)
    Example: https://api.ev.energy/v2/problems/example-problem/

  - `status` (number)
    Example: 400

  - `title` (string, required)
    Example: Short description

  - `detail` (string, required)
    Example: Long, more specific description.

  - `instance` (string)
    Example: https://api.ev.energy/v2/users/user01HN2P75GBNFRJPCZJXEFVXH5E

  - `notification` (object)
    Something that the user should be informed about.

  - `notification.id` (string, required)
    Unique identifier for the Notification
    Example: notf67O36PLTFDB57M0E5L33JZLGM0

  - `notification.url` (string, required)
    Example: https://api.ev.energy/notifications/notf67O36PLTFDB57M0E5L33JZLGM0

  - `notification.message_id` (string, required)
    Internal identifier for this notification type. E.g. 'ERR0023'

  - `notification.category` (string, required)
    Category of this notification type
    Enum: "ACTIONABLE", "SERVICE", "RETRY", "MARKETING", "INTERNAL"

  - `notification.event_time` (string, required)
    The timestamp of the event described by this notification

  - `notification.short_text_title` (string, required)
    Short title for the notification

  - `notification.short_text_body` (string, required)
    Short description of the event being notified

  - `notification.detail_page_title` (string, required)
    Title of a help page giving more information about this notification

  - `notification.detail_page_body` (string, required)
    Text of a help page giving more information about this notification

  - `notification.external_link` (string | null, required)
    URL of a web page giving further information about this notification

  - `notification.external_button_label` (string, required)
    Text to be displayed on a button leading to the external_link location

  - `notification.read_at` (string)
    When the user examined the contents of this notification

  - `notification.resolved_at` (string)
    When the problem associated with this notification was resolved

## Response 429 headers (application/problem+json):

  - `EvEnergy-Version` (number)
    Indicates the version of the API that generated this response. If EvEnergy-Version was not specified in the request, this will be your OAuth application's default version.
    Enum: "2"

  - `Retry-After` (number)
    The number of seconds until this client's requests will not be rate limited.

  - `X-RateLimit-Limit` (number)
    The maximum number of requests that can be made to this endpoint per hour. Defaults to 1000 but may vary per client.

  - `X-RateLimit-Remaining` (number)
    The number of requests remaining until this client's rate limit is reached.

## Response 201 examples:

  - `A custom GB tariff with weekday, weekend and public holiday rates` (unknown)

## Response 400 examples:

  - `Request failed validation` (unknown)

## Response 422 examples:

  - `Request failed validation` (unknown)

## Response 429 examples:

  - `Example 1` (unknown)

