TOU webhooks

Tell your app
when peak starts.

A signed POST when a time-of-use period flips — off-peak to on-peak, and every other boundary. No cron. No polling /query/current.

Example weekday on PG&E E-TOU-C (ZIP 94103). On-peak 4–9 PM. Hours vary by utility, season, and plan — that is the point of the webhook.

Don’t Poll the Tariff Clock

A 15-minute cron on /query/current spends quota to learn something that happens a handful of times a day. The webhook is the flip itself.

Polling
# crontab — every 15 minutes
curl -s \
  -H "Authorization: Bearer tou_…" \
  ".../query/current?zip_code=94103"

~2,880 calls/month to notice a 4 PM flip. Miss the minute, or hammer the quota.

Webhook
POST /hooks/tou
{
  "type": "tou.period.changed",
  "previous_period": "off_peak",
  "period": "on_peak"
}

One signed delivery at the boundary. Your server reacts. Polling quota stays unused.

URL in. Peak-start out.

Three steps in the dashboard. The first observation of each plan is recorded silently — you only get events on real transitions.

1

Create an endpoint

Paste an HTTPS URL. You get a signing secret (tousec_…), shown once. Store it.

2

Watch locations

Add (ZIP, customer_class) pairs. One endpoint can cover every location in your plan.

3

Handle the flip

When period is on_peak, peak started. Respond 2xx. Shed load, pause chargers, raise reserve.

One POST, one period change

A tou.period.changed body for one rate plan at one watched ZIP. Copy it, then wire a 2xx handler. Signature, retries, and headers live in the docs — this page does not duplicate them.

POST body · application/json
{
  "id": "evt_8f3a2c104b6d4e9a9f12",
  "type": "tou.period.changed",
  "created_at": "2026-05-16T16:00:00-07:00",
  "zip_code": "94103",
  "customer_class": "residential",
  "previous_period": "off_peak",
  "period": "on_peak",
  "next_change_at": "2026-05-16T21:00:00-07:00",
  "rate_plan": {
    "id": "8f3a2c10-4b6d-4e9a-9f12-7c5e1d8a0b34",
    "utility_number": 14328,
    "utility_name": "Pacific Gas & Electric Co",
    "code": "E-TOU-C",
    "name": "Residential Time-of-Use"
  }
}

A ZIP that resolves to several plans sends one event per plan that changed. previous_period / period use the same names as the REST API.

python · one endpoint
# POST /hooks/tou
# verify Tou-Signature first — /docs/#webhooks

@app.post("/hooks/tou")
def on_period_changed():
    event = request.get_json()
    if event["period"] == "on_peak":
        pause_chargers(event["zip_code"])
    return ("", 200)

That is the whole job: branch on period, ack with 2xx. Set the endpoint up in the webhooks dashboard.

The peak-start POST, put to work

EV charging

Pause Wall Connectors and depot stalls when period becomes on_peak. Resume on off_peak or super_off_peak.

HVAC

Pre-cool from next_change_at on the prior event, then coast when this one says on-peak. No hardcoded 4 PM.

Home battery / VPP

Raise reserve and discharge at peak start. Period names only — this API never sends ¢/kWh.

Multi-site

One endpoint, many ZIPs. Shed HVAC and lighting in each territory as that utility’s peak starts, not yours.

Fleet / depot

Hold charging across service territories until off-peak returns. High-volume sites stay off the polling loop.

Your worker

Flask, FastAPI, n8n, Temporal — anything that accepts a POST. Home Assistant can keep polling; webhooks are for a server you own.

Signed, retried, logged

Each delivery is HMAC-SHA256 over {timestamp}.{body}, Stripe-style. Verify Tou-Signature before you trust the JSON. Respond 2xx or we retry: immediately, then 1 min, 5 min, 30 min, 2 h.

Every attempt lands in the webhooks dashboard with status, HTTP code, and attempt count. The full verify recipe is in the period-change docs.

Tou-Signature
HMAC-SHA256 hex digest, keyed with your tousec_… secret.
Tou-Timestamp
Unix seconds when we signed. Reject anything too old — replay defense.
Tou-Webhook-Id
The event id. Deliveries retry, so dedupe on this.

Frequently asked

  1. How do I get notified when peak starts?

    Register a webhook endpoint and watch a ZIP. When that location’s period changes, tou.tools sends a signed tou.period.changed event. If previous_period is off_peak and period is on_peak, peak just started.

  2. What is a TOU webhook?

    A signed HTTP POST fired when a time-of-use period changes — off-peak to on-peak, and every other boundary — for a location you watch. It replaces polling GET /query/current just to learn that the clock flipped.

  3. Do I still need to poll /query/current?

    Not for period changes. Poll when you need the period right now — a dashboard, a one-shot agent call. Use the webhook when your server should react as the tariff clock flips.

  4. Are webhooks on the free plan?

    No. Webhooks start on Builder: 3 endpoints, 10 on Growth, 25 on Business, unlimited on Enterprise. Each endpoint can watch any of the locations in your plan. Get a free key, then upgrade when you are ready to push events.

  5. Does this include ¢/kWh prices?

    No. tou.tools is the timing layer: period names and clock boundaries. The payload has previous_period, period, next_change_at, ZIP, and the rate plan — not prices.

  6. What if my server is down?

    Non-2xx and timeouts retry: immediately, then 1 min, 5 min, 30 min, 2 h. Dedupe on Tou-Webhook-Id. Every attempt is logged on the webhooks dashboard.

Start With a Free Key

No credit card. Webhooks ship on Builder — three endpoints, any of your locations. Create the key first, upgrade when you want the POST.

Get Free API Key