# Lightning Signet Faucet > Free Bitcoin **signet** sats over Lightning. No login, no CAPTCHA, no API key. > A claim is gated by proof of work instead of a human check, so scripts, CI > jobs, and autonomous agents can use it exactly like a person can. Signet coins are test coins with no monetary value. This faucet pays the **signet** network only — invoices must start with `lntbs`. ## Right now - Status: not serving claims - Pays per claim: 1000 sat - Proof-of-work difficulty: 26 leading zero bits - Challenge lifetime: 600 seconds These change with demand and liquidity. Read `/api/status` before each claim rather than hardcoding them. ## Fastest path ``` curl -sSL https://lightningsignetfaucet.com/claim.sh | sh -s -- ``` Takes a challenge, grinds it, redeems it, and polls until the payment settles. Needs python3 or node — the grind is a few million SHA-256 rounds, which a shell loop cannot do at a usable speed. ## The API Three calls. Every response is JSON. Every error carries a stable `error` code, a human-readable `hint`, and a `retry` object saying what to do next. ### 1. GET /api/challenge Returns a signed, single-use, expiring challenge. ```json { "challenge": "v1:::::.", "difficulty": 26, "expires_at": 1785400000, "amount_sat": 1000 } ``` ### 2. Solve it locally Find any `nonce` such that `sha256(challenge + nonce)` has at least `difficulty` **leading zero bits**. The concatenation is plain UTF-8 with no separator, and `challenge` is the entire string including its `.` suffix. The nonce may be any 1–128 character URL-safe string; counting up in base 16 or 36 is fine. Expect roughly `2^difficulty` hashes on average — about 67M at the current setting, a second or two of one CPU core. ### 3. POST /api/claim ```json { "bolt11": "lntbs...", "challenge": "...", "nonce": "..." } ``` Returns `202` with the claim object below. The invoice must be for signet and must carry an explicit amount. **`amount_sat` is a ceiling, not a fixed payout.** An invoice for less than `amount_sat` is accepted and paid at its own smaller amount — you are not topped up to the advertised figure, and nothing warns you. Only an invoice for *more* than `amount_sat` is rejected (`amount_too_large`). Mint your invoice for exactly `amount_sat` unless you deliberately want less. Order matters: read `amount_sat` from `/api/status` or `/api/challenge` **before** minting the invoice. It moves with liquidity and demand, so an invoice minted against a stale figure either underpays you silently (if the figure rose) or is rejected outright (if it fell). ### 4. GET /api/claims/:id Poll every ~5 seconds. Payment is asynchronous and normally settles in 5–15 seconds; never assume a claim succeeded without polling. This returns the same object `POST /api/claim` did — that endpoint adds only `poll` on top, so one shape covers a claim's whole lifetime. ```json { "claim_id": "…", "status": "settled", "lane": "free", "amount_sat": 1000, "fee_sat": 1, "payment_hash": "…", "rail": "SEND_RAIL_IN_ARK", "created_at": 1785400000, "updated_at": 1785400009 } ``` `status` is `pending`, `settled`, or `failed`. A failed claim carries `failure_reason`. A claim still pending past its expected window carries `stalled: true` — reported, not given up on, since a slow swap may still land. `payment_hash` is the invoice's own hash, so you can match a claim against your node's records. `rail` reports the route waved chose (`SEND_RAIL_IN_ARK` for an internal transfer, otherwise a swap out to Lightning); it is informational and safe to ignore. ### GET /api/status Machine-readable liquidity, caps, current difficulty, and whether the faucet can serve claims at all. ## Error codes | code | meaning | what to do | | --- | --- | --- | | `pow_insufficient_work` | the nonce does not meet the difficulty | grind further | | `pow_bad_signature` | challenge was not issued here, or was altered | take a fresh challenge | | `pow_expired` | challenge aged out | take a fresh challenge | | `token_already_used` | that challenge was already redeemed | take a fresh challenge | | `amount_too_large` | invoice asks for more than one claim pays | issue an invoice for `amount_sat` | | `wrong_network` | invoice is not signet | issue an `lntbs` invoice | | `amountless_invoice` | invoice has no amount | issue one with an explicit amount | | `bad_amount` | amount is not a positive whole number of sats | round to whole sats | | `undecodable_invoice` | bolt11 did not parse | check the string was not truncated | | `invoice_already_claimed` | that invoice already has a claim in flight | poll the existing claim | | `outflow_cap_reached` | faucet hit its rolling payout cap | honour `retry.after_ms` | | `liquidity_floor` | faucet is low on signet liquidity | retry after ~30s | | `fee_too_high` | no acceptably cheap route to that invoice | retry after ~60s, or use a better-connected node | | `payment_failed` | the send itself failed; `detail` says why | the challenge is spent — take a fresh one | | `wallet_not_ready` | dispenser wallet is locked or starting | retry shortly | | `wallet_unavailable` | dispenser wallet did not respond | retry shortly | | `unknown_claim` | no claim with that id | check the `claim_id` | | `dispatcher_unavailable` | backend not responding | retry after ~10s | Errors that can name a wait carry a `retry` object with `after_ms`; prefer it over a fixed backoff, since it is computed from real faucet state rather than guessed. `outflow_cap_reached` in particular is a rolling window that can be hours wide — do not busy-poll it. ## Rules that matter - **One claim per challenge.** Challenges are single-use; a solution cannot be ground once and replayed. Take a new challenge for every claim. - **Difficulty is signed into the challenge.** Editing it invalidates the HMAC. - **A rejected claim does not consume the challenge**, so a claim refused for a bad amount, a duplicate invoice, a cap or thin liquidity can be re-sent with the same work. The one exception is `payment_failed`: once the send has been attempted we cannot prove it did not land, so the challenge stays spent and you must take a fresh one. - **Be polite.** Difficulty rises automatically with demand; hammering the faucet makes it slower for you, not faster. There is no per-caller rate limit and no throttling `429` beyond `outflow_cap_reached`: the proof-of-work curve *is* the throttle, so sustained load costs you CPU rather than errors. - **Browsers are welcome.** Every `/api/` route sends `Access-Control-Allow-Origin: *` and answers preflight, so a browser-side agent can call this directly. No route takes credentials or cookies.