# RoofIgnite supply API

For lead sellers. Two questions, answered in one call each:

1. Do you have a contractor in this ZIP who can take a lead right now?
2. Will you pay this much for a lead there?

Base URL: `https://coverage.roofignite.com/api/coverage`
No API key. No account. CORS is open, so it works from a browser, a script, or an agent.
Rate limit: 120 requests per minute per IP.

Nothing about a homeowner ever goes into this API. Do not send names, phones, emails or addresses to it.

---

## 1. Check one ZIP

```bash
curl "https://coverage.roofignite.com/api/coverage?action=check&zip=48505"
```

```json
{ "ok": true, "zip": "48505", "covered": true, "accepting": true, "state": "MI" }
```

- `covered` — a contractor of ours has this ZIP in their service area.
- `accepting` — that contractor can take a lead today, meaning they are not paused and not at their daily cap.

`covered: true, accepting: false` means come back tomorrow, not never.

## 2. Check many ZIPs at once

Up to 200 per call. This is the fast way to map your out-of-area volume against our coverage.

```bash
curl -X POST https://coverage.roofignite.com/api/coverage \
  -H 'Content-Type: application/json' \
  -d '{"action":"bulk","zips":["48505","38632","90210","33024"]}'
```

```json
{ "ok": true, "count": 4, "accepting": 2,
  "results": {
    "48505": { "covered": true,  "accepting": true,  "state": "MI" },
    "38632": { "covered": true,  "accepting": true,  "state": "MS" },
    "33024": { "covered": false, "accepting": false, "state": "FL" },
    "90210": { "covered": false, "accepting": false, "state": null }
  } }
```

## 3. Propose a price

You name the price. We answer accept or decline. We do not publish what we pay, because it varies by ZIP and by which contractor is covering it.

```bash
curl -X POST https://coverage.roofignite.com/api/coverage \
  -H 'Content-Type: application/json' \
  -d '{"action":"quote","zip":"48505","price":60}'
```

```json
{ "ok": true, "quote_id": "q_4cwvf8lr", "zip": "48505", "state": "MI",
  "price_usd": 60, "decision": "accept", "reason": "ok",
  "covered": true, "accepting": true,
  "expires_at": "2026-09-09T19:41:29.691Z", "binding": false }
```

`decision` is `accept` or `decline`. `reason` is one of:

| reason | meaning |
|---|---|
| `ok` | we will buy at that price |
| `not_covered` | no contractor of ours in that ZIP, send it to a marketplace |
| `at_capacity_today` | we cover it, but today's cap is full |
| `above_our_price_here` | covered and open, your price is higher than we pay in that ZIP. Propose lower. |

A quote is **indicative and not binding**. It tells you whether it is worth a conversation. Leads are only accepted from sellers with a signed one-page agreement and an API key, because that is where the consent, returns and payment terms live.

---

## Errors

| status | body | meaning |
|---|---|---|
| 400 | `bad_zip` | five digit US ZIP codes only |
| 400 | `bad_price` | price is USD per lead, greater than zero |
| 400 | `too_many` | more than 200 ZIPs in one bulk call |
| 429 | `rate_limited` | back off 60 seconds |
| 503 | `unavailable` | our side is down, retry, do not treat as "not covered" |

Treat a 503 as unknown, never as a decline. That is the one failure mode that would cost you money.

---

## What happens after an accept

1. You tell us the volume and states you have, we send a one-page agreement.
2. We issue an API key and a posting spec, about half a day of work for a developer. A webhook or an emailed batch is fine for a first round.
3. Leads must carry consent text, timestamp and a certificate. We verify the phone on our side too.
4. Returns: 48 hours, defined reasons, reviewed by a person. A homeowner not answering the phone is not a return.
5. Weekly statement, closed Sunday, paid within 7 days. No prepay, no wallet, no card on file.

Contact: the coverage page at https://coverage.roofignite.com

---

## Drop this into Claude Code

Save this file in your project and give your agent this instruction:

> Read `supply-api.md`. Using the RoofIgnite supply API, take my out-of-area ZIP list in `<your file>`, call the bulk endpoint in batches of 200, and tell me which ZIPs they can take leads in today. Then for the ZIPs that come back accepting, call the quote endpoint at the price I currently get from my aggregator plus $15 and report which ones accept. Do not send any homeowner data to this API. Treat a 503 as unknown rather than a decline, and respect the 120 requests per minute limit.

The API is read-only and takes no personal data, so an agent can safely explore it without a key.
