> ## Documentation Index
> Fetch the complete documentation index at: https://offergrid.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Electricity Offers

> Publish deregulated retail electricity plans with the structured .electricity contract

## Overview

Electricity is a first-class service type on Offergrid. Rather than a
free-form JSON blob, electricity offers carry a single, structured
**`electricity`** object grouped into four sections — **rate**, **term**,
**plan**, and **disclosures** — that models a deregulated retail electricity
plan the way a Texas [Electricity Facts Label
(EFL)](https://www.puc.texas.gov/consumer/electricity/Documents/facts.pdf) does.

<Info>
  This page is the narrative guide. The field-by-field reference is published in
  the [API Reference](/docs/api-reference/introduction) as the
  `ElectricityContractWrite`, `ElectricityContract`, and `ElectricityCharge`
  schema components.
</Info>

## Identifying an electricity offer

Every offer response carries a top-level **`serviceType`** discriminator that
mirrors `category` — check either field:

```jsonc theme={null}
{
  "id": "…",
  "serviceType": "electricity",
  "category": "electricity",
  "name": "Amigo Fixed 12",
  "status": "active",
  "electricity": { /* the contract, see below */ }
}
```

Electricity offers additionally include the grouped **`electricity`** object.
Other service types (`internet`, `other`) get their own top-level key.

## The `electricity` contract

```jsonc theme={null}
"electricity": {
  "rate": {
    "type": "fixed",                       // fixed | variable | indexed
    "charges": [ /* bill breakdown — the source of truth, see below */ ],
    "avgPriceAt1000Kwh": 16.2,             // ¢/kWh, the all-in EFL comparison number
    "estimatedMonthlyAt1000Kwh": 162.00    // READ-ONLY — derived from charges
  },
  "term": {
    "length": "months_12",                 // no_contract | month_to_month | months_12 | months_24 | months_36
    "earlyTerminationFee": 150,            // dollars
    "earlyTerminationFeeNotes": "Prorated by months remaining"
  },
  "plan": {
    "renewablePercentage": 100,            // 0–100
    "freeNightsWeekends": false,
    "noDeposit": true
  },
  "disclosures": {                         // Texas PUCT regulatory disclosures
    "electricityFactsLabel": {
      "url": "https://example.com/efl.pdf",
      "versionId": "EFL-2024-001",
      "avgPrice500kwh": 17.1,
      "avgPrice1000kwh": 16.2,
      "avgPrice2000kwh": 15.4,
      "renewablePercent": 100
    },
    "puctCertNumber": "10081",
    "puctCertifiedName": "Amigo Energy",
    "termsOfServiceUrl": "https://example.com/tos.pdf",
    "yourRightsUrl": "https://example.com/yrac.pdf"
  }
}
```

All four sections and all fields are optional on write, **except** the [publish
requirement](#publishing-requirements). Send only what you have; unspecified
fields are left untouched on update.

<AccordionGroup>
  <Accordion title="rate — how customers are billed">
    * **`type`** — `fixed`, `variable`, or `indexed`.
    * **`charges`** — the ordered provider (REP) + utility (TDU) charge lines
      that define pricing. This is the source of truth — see
      [The charge breakdown](#the-charge-breakdown-rate-charges).
    * **`avgPriceAt1000Kwh`** — the EFL "average price at 1000 kWh" comparison
      number, in ¢/kWh (all-in).
    * **`estimatedMonthlyAt1000Kwh`** — read-only dollar headline, derived from
      `charges` (ignored on write).
  </Accordion>

  <Accordion title="term — contract length and cancellation">
    * **`length`** — `no_contract`, `month_to_month`, `months_12`, `months_24`,
      or `months_36`.
    * **`earlyTerminationFee`** — cancellation fee in dollars.
    * **`earlyTerminationFeeNotes`** — free-text detail, e.g. "Prorated by months
      remaining".
  </Accordion>

  <Accordion title="plan — green energy and perks">
    * **`renewablePercentage`** — 0–100.
    * **`freeNightsWeekends`** — boolean.
    * **`noDeposit`** — boolean.
  </Accordion>

  <Accordion title="disclosures — Texas PUCT regulatory documents">
    * **`electricityFactsLabel`** — the EFL: `url`, `versionId`, and the three
      benchmark prices (`avgPrice500kwh`, `avgPrice1000kwh`, `avgPrice2000kwh`)
      plus `renewablePercent`.
    * **`puctCertNumber`** / **`puctCertifiedName`** — your PUCT REP
      certification.
    * **`termsOfServiceUrl`** / **`yourRightsUrl`** — the Terms of Service and
      Your Rights as a Customer documents.
  </Accordion>
</AccordionGroup>

## Creating an electricity offer

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.offergrid.io/provider/offers \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Amigo Fixed 12",
      "category": "electricity",
      "electricity": {
        "rate": {
          "type": "fixed",
          "charges": [
            { "type": "perKwh", "owner": "provider", "label": "Energy Charge", "centsPerKwh": 12.5 },
            { "type": "fixed",  "owner": "utility",  "label": "TDU Meter Charge", "amountDollars": 4.39 },
            { "type": "perKwh", "owner": "utility",  "label": "TDU Delivery", "centsPerKwh": 4.2 }
          ]
        },
        "term": { "length": "months_12", "earlyTerminationFee": 150 },
        "plan": { "renewablePercentage": 100, "noDeposit": true },
        "disclosures": {
          "puctCertNumber": "10081",
          "electricityFactsLabel": { "url": "https://example.com/efl.pdf" }
        }
      }
    }'
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch('https://api.offergrid.io/provider/offers', {
    method: 'POST',
    headers: {
      'x-api-key': process.env.OFFERGRID_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      name: 'Amigo Fixed 12',
      category: 'electricity',
      electricity: {
        rate: {
          type: 'fixed',
          charges: [
            { type: 'perKwh', owner: 'provider', label: 'Energy Charge', centsPerKwh: 12.5 },
            { type: 'fixed',  owner: 'utility',  label: 'TDU Meter Charge', amountDollars: 4.39 },
            { type: 'perKwh', owner: 'utility',  label: 'TDU Delivery', centsPerKwh: 4.2 },
          ],
        },
        term: { length: 'months_12', earlyTerminationFee: 150 },
        plan: { renewablePercentage: 100, noDeposit: true },
        disclosures: {
          puctCertNumber: '10081',
          electricityFactsLabel: { url: 'https://example.com/efl.pdf' },
        },
      },
    }),
  });

  const offer = await response.json();
  ```
</CodeGroup>

The response is the created offer with `serviceType: "electricity"`, the
projected `electricity` object (now including the derived
`rate.estimatedMonthlyAt1000Kwh`), and the standard offer fields.

## Updating an electricity offer

Send only the sections you're changing. The `electricity` object is **merged**
onto the stored offer, so unrelated data is preserved:

```jsonc PATCH /provider/offers/{id} theme={null}
{
  "electricity": {
    "term": { "earlyTerminationFee": 200 },
    "plan": { "renewablePercentage": 100 }
  }
}
```

This changes only the early termination fee and renewable percentage; the
existing rate, charges, and disclosures are untouched, and the derived headline
is recomputed.

<Warning>
  The `electricity` object is the **only** way to set an electricity offer's
  pricing, term, plan, and disclosures — there is no flat/free-form
  alternative field to fall back to.
</Warning>

## The charge breakdown (`rate.charges`)

A deregulated retail electricity bill has two legally distinct parts (Texas PUCT
Rule 25.475 / the EFL): charges set by the **provider** (REP) and pass-through
delivery charges set by the local **utility** (TDU, e.g. Oncor). `rate.charges`
is an ordered list of charge lines that captures both, plus usage-tiered charges
and threshold bill credits.

Each charge line:

| Field                         | Applies to        | Meaning                                                                |
| ----------------------------- | ----------------- | ---------------------------------------------------------------------- |
| `type`                        | all               | `perKwh` \| `fixed` \| `credit`                                        |
| `owner`                       | all               | `provider` (REP) \| `utility` (TDU)                                    |
| `label`                       | all               | Display name, e.g. `"Energy Charge"`, `"TDU Delivery"`                 |
| `centsPerKwh`                 | `perKwh`          | Rate in ¢/kWh                                                          |
| `amountDollars`               | `fixed`, `credit` | Dollar amount (credits entered **positive**, subtracted from the bill) |
| `minUsageKwh` / `maxUsageKwh` | optional          | Usage band (see below)                                                 |

**Usage bands:**

* `perKwh` bills only the kWh inside the band — `"12¢ for the first 500 kWh"` is
  `{ "minUsageKwh": 0, "maxUsageKwh": 500 }`; `"15¢ above 500 kWh"` is
  `{ "minUsageKwh": 500 }`.
* `fixed` / `credit` applies only when **total** usage falls inside the band —
  e.g. `"$125 credit if usage ≥ 1000 kWh"` is a credit with
  `{ "minUsageKwh": 1000 }`.

### Bill estimate math

Offergrid folds `charges` into an itemized bill at any usage level. Line amounts
are rounded to cents individually; subtotals and totals are sums of the rounded
lines, so a breakdown always reconciles. Worked example at **1000 kWh** for the
create payload above:

| Line             | Owner    | Calculation      | Amount       |
| ---------------- | -------- | ---------------- | ------------ |
| Energy Charge    | provider | 12.5¢ × 1000 kWh | \$125.00     |
| TDU Meter Charge | utility  | flat             | \$4.39       |
| TDU Delivery     | utility  | 4.2¢ × 1000 kWh  | \$42.00      |
| **Total**        |          |                  | **\$171.39** |

* Provider subtotal = \$125.00
* Utility subtotal = \$46.39
* Total = **\$171.39**
* Effective all-in rate = 171.39 × 100 ÷ 1000 = **17.139 ¢/kWh** (the EFL metric)

`rate.estimatedMonthlyAt1000Kwh` in the response is this total at 1000 kWh.

## Publishing requirements

`POST /provider/offers/{id}/publish` validates the offer. For electricity, the
one contract-specific rule is:

<Check>
  `rate.charges` must include **at least one provider `perKwh` energy charge**.
</Check>

If it doesn't, publish returns `400` with structured `validationErrors` pointing
at `electricityDetails.charges`. General offer requirements — name, SKU,
description, at least one market, etc. — also apply.

## Derived and read-only fields

* **`rate.estimatedMonthlyAt1000Kwh`** is computed from `rate.charges`. It is
  output-only — setting it on a write has no effect.
* Offergrid mirrors this figure into the generic `monthlyPrice` column so
  electricity offers sort and filter alongside fixed-price offers.

## Storage

Electricity offer data lives in a dedicated typed relation — there is no
free-form JSON blob involved. `charges` is the only accepted rate
representation in the `electricity` contract; you never have to branch on a
flat legacy rate format. Read everything electricity-related from
`.electricity`.

## Quick reference

| You want to…                | Use                                                                |
| --------------------------- | ------------------------------------------------------------------ |
| Detect an electricity offer | top-level `serviceType === "electricity"`                          |
| Read pricing                | `electricity.rate.charges` (+ derived `estimatedMonthlyAt1000Kwh`) |
| Read term / ETF             | `electricity.term`                                                 |
| Read green %, perks         | `electricity.plan`                                                 |
| Read EFL / PUCT             | `electricity.disclosures`                                          |
| Set pricing                 | send `electricity.rate.charges` on create/update                   |
| Publish                     | ensure ≥1 provider `perKwh` charge, then `POST …/publish`          |

## Next steps

<CardGroup cols={2}>
  <Card title="Creating Offers" icon="plus-circle" href="/docs/providers/creating-offers">
    The general offer create/publish flow
  </Card>

  <Card title="Service Categories" icon="tags" href="/docs/providers/offer-categories">
    Fields for internet, electricity, and the other category
  </Card>

  <Card title="API Integration" icon="plug" href="/docs/providers/api-integration">
    Automate offer sync and order processing
  </Card>

  <Card title="API Reference" icon="code" href="/docs/api-reference/introduction">
    The `ElectricityContract` schema, field by field
  </Card>
</CardGroup>
