# Aurora Solar Webhooks

Aurora Solar (solar design software) fires a webhook when something happens in your tenant: a
project or design is created, a job finishes, an agreement changes status. Each webhook is a
**GET request with no body**. The event data (identifiers and statuses) arrives in the **query
string**, built from a URL template you provide. Webhooks are **not signed**, so your endpoint
authenticates them with a secret header you add to the subscription.

> Set header_auth_key and header_auth_value on the Aurora Solar webhook and enter them here. Webhooks without them send nothing to verify.

## When to Use This Skill

* How do I receive Aurora Solar webhooks?
* How do I authenticate Aurora Solar webhooks (`header_auth_key` / `header_auth_value`)?
* Does Aurora Solar sign webhook payloads? (No: use a secret header)
* How do I read `project_id` and `design_id` from an Aurora webhook URL?
* How do I handle `project_created`, `design_created` or `performance_simulation_job_completed`?
* Why does my Aurora Solar webhook endpoint return 401?

## Verification (core)

```javascript
const crypto = require('crypto');

// Hash both sides: equal-length buffers, so timingSafeEqual never throws.
function safeEqual(a, b) {
  const ha = crypto.createHash('sha256').update(String(a)).digest();
  const hb = crypto.createHash('sha256').update(String(b)).digest();
  return crypto.timingSafeEqual(ha, hb);
}

function verifyAuroraSolarRequest(
  headers,
  secret = process.env.AURORA_SOLAR_WEBHOOK_SECRET,
  headerName = process.env.AURORA_SOLAR_WEBHOOK_HEADER || 'X-Aurora-Webhook-Token'
) {
  if (!secret) return false;                            // never accept when unconfigured
  const received = headers[headerName.toLowerCase()];   // Node lowercases header names
  return Boolean(received) && safeEqual(received, secret); // whole value, no Bearer parsing
}

```

* The header name is **user-chosen** (`header_auth_key`). Aurora's docs use `X-Aurora-Webhook-Token`;
  the examples read the name from `AURORA_SOLAR_WEBHOOK_HEADER` (default `X-Aurora-Webhook-Token`).
* The expected value is `AURORA_SOLAR_WEBHOOK_SECRET`: the exact, whole `header_auth_value`,
  including any `Bearer ` prefix you typed. Look the header up case-insensitively and compare the
  whole value; do not strip or parse a prefix.
* Check the header **first**, then read the query parameters. Missing header or mismatch: `401`.
* Python: `hmac.compare_digest` on **bytes** (encode both sides; `str` raises on non-ASCII).
* Read any body raw (`express.raw({ type: '*/*' })`); Aurora sends none, but a proxy might.

> **A static shared credential authenticates the sender, not the body, and gives no replay
> protection** (no signature, no timestamp). Use an HTTPS URL, and rotate the header value on the
> subscription if it leaks. Aurora also offers Basic Auth; Hookdeck's Aurora Solar source does not
> cover it, so use header-based token authentication.

> **For complete handlers with tests**, see [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/aurora-solar-webhooks/examples/express/), [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/aurora-solar-webhooks/examples/nextjs/), [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/aurora-solar-webhooks/examples/fastapi/).

## Webhook URL Template

Aurora fires GET requests to a URL generated from a template you provide when creating the
subscription (`url_template`). Placeholders are upper-case attribute names in angle brackets.
Each subscription is for **one event**, so put a static `event` parameter in the template and
dispatch on it:

```
https://<hookdeck-url>?event=project_created&project_id=<PROJECT_ID>&source=<SOURCE>

```

Aurora fills in the attributes, so the request looks like
`GET /?event=project_created&project_id=3fa8...&source=api`. Hookdeck's Aurora Solar source
pre-selects GET without managing the method; the receivers also accept POST for flexibility.
Respond within 10 seconds; failures (timeout, 3xx/4xx/5xx) are retried 5 more times over 24 hours.

## Event Types

The event is the subscription's `event` (the docs list 32). Common ones:

| Event | Sent When |
| --- | --- |
| `project_created` | A project is created (`project_id`, `source`, `order_id`) |
| `project_changed` | Project attributes change (`project_id`, `source`, `attributes`) |
| `project_status_changed` | Project status changes (`project_id`, `status`; any string) |
| `design_created` | A design is created (`project_id`, `design_id`, `source`) |
| `performance_simulation_job_completed` | A performance simulation finishes (`design_id`, `job_id`, `status`, `source`) |
| `agreement_status_changed` | An agreement is sent, signed, canceled, etc. |
| `web_proposal_viewed` | A web proposal is viewed (`design_id`, `project_id`, `is_first_view`) |

See [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/aurora-solar-webhooks/references/overview.md) for all 32 events and their attributes.

## Environment Variables

```bash
AURORA_SOLAR_WEBHOOK_HEADER=X-Aurora-Webhook-Token   # your header_auth_key
AURORA_SOLAR_WEBHOOK_SECRET=your-header-auth-value   # your exact, whole header_auth_value

```

## Local Development

Aurora can't reach `localhost`. Tunnel with the Hookdeck CLI (no account required):

```bash
npx hookdeck-cli listen 3000 aurora-solar --path /webhooks/aurora-solar

```

Use the printed URL (with your `?event=...` template) as the webhook URL in Aurora.

## Resources

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/aurora-solar-webhooks/references/overview.md) - What Aurora Solar webhooks are, events and URL attributes
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/aurora-solar-webhooks/references/setup.md) - Create a subscription with header-based token authentication
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/aurora-solar-webhooks/references/verification.md) - Header check details, gotchas, debugging 401s
* [examples/](https://github.com/hookdeck/webhook-skills/tree/main/skills/aurora-solar-webhooks/examples/) - Runnable Express, Next.js and FastAPI handlers with tests