{"info":{"name":"SignedOff API","description":"The SignedOff Permit Data API returns live building-permit status pulled from\nofficial city and county portals, so you never scrape a portal or manage a\ngovernment login yourself.\n\n## Coverage\n\nThe jurisdiction is detected automatically from the permit number. Supported\nportal families include **LADBS** (City of Los Angeles), **Accela Citizen\nAccess** cities, **EPIC-LA** (LA County), and **EnerGov** jurisdictions, with\nnew cities added regularly. `GET /api/v1/jurisdictions` returns the live,\nauthoritative list.\n\n## What you can do\n\n- **Permit status** — `GET /api/v1/permits/{permit_number}/status`. The\n  jurisdiction is auto-detected from the permit number; when several match\n  (common across Accela cities) the API responds `300` so you can retry with\n  `?jurisdiction=`.\n- **Batch lookups** — `POST /api/v1/permits/batch-status` for up to 25 permits\n  in one call; cache hits return immediately, misses trigger concurrent scrapes.\n- **Inspections & history** — per-permit inspection records and the full\n  status-change timeline.\n- **Jurisdictions** — list supported areas, coverage stats and analytics, and\n  request a new one.\n- **Webhooks** — subscribe to `status_change` events with signed, automatically\n  retried deliveries instead of polling.\n\n## Data freshness\n\nResponses serve recently cached data when it is still fresh and fall back to a\nlive scrape otherwise, so you always see current portal state. Paid plans can\nforce a live re-scrape with `?force_refresh=true`.\n\n## Try it without an account\n\nAnonymous requests and sandbox keys (`sk_test_…`) return a curated demo dataset\nwith the exact response shape of live data — copy-paste from the\n[playground](https://signedoff.io/developers/playground) into production\nunchanged.\n\nAuthenticate live requests with the **`X-API-Key`** header. Sign up free at\nhttps://signedoff.io/developers/signup.\n","schema":"https://schema.getpostman.com/json/collection/v2.1.0/collection.json","version":"1.0.0"},"auth":{"type":"apikey","apikey":[{"key":"key","value":"X-API-Key","type":"string"},{"key":"value","value":"{{api_key}}","type":"string"},{"key":"in","value":"header","type":"string"}]},"variable":[{"key":"base_url","value":"","type":"string"},{"key":"api_key","value":"sk_live_replace_with_your_key","type":"string"}],"item":[{"name":"Get permit status","request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/api/v1/permits/:permit_number/status","host":["{{base_url}}"],"path":["api","v1","permits",":permit_number","status"],"variable":[{"key":"permit_number","value":""}]},"description":"Look up the current status of a building permit. Returns cached data if available, or triggers a live scrape for supported jurisdictions. When multiple jurisdictions match (common with Accela cities), pass ?jurisdiction=slug to specify which one."},"response":[]},{"name":"Batch permit status lookup","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"url":{"raw":"{{base_url}}/api/v1/permits/batch-status","host":["{{base_url}}"],"path":["api","v1","permits","batch-status"],"variable":[]},"description":"Look up status for multiple permits (max 25). Cached permits return immediately; cache misses trigger concurrent live scrapes.","body":{"mode":"raw","raw":"{\n  \"// see API docs for body schema\": true\n}","options":{"raw":{"language":"json"}}}},"response":[]},{"name":"Get permit inspections","request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/api/v1/permits/:permit_number/inspections","host":["{{base_url}}"],"path":["api","v1","permits",":permit_number","inspections"],"variable":[{"key":"permit_number","value":""}]},"description":"Returns inspection history and pending inspections from permit scrape data."},"response":[]},{"name":"Get permit status history","request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/api/v1/permits/:permit_number/history","host":["{{base_url}}"],"path":["api","v1","permits",":permit_number","history"],"variable":[{"key":"permit_number","value":""}]},"description":"Returns status change timeline from portal scrape data and SignedOff sync logs."},"response":[]},{"name":"List supported jurisdictions","request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/api/v1/jurisdictions","host":["{{base_url}}"],"path":["api","v1","jurisdictions"],"variable":[]},"description":"Public endpoint listing all jurisdictions SignedOff can monitor. No authentication required."},"response":[]},{"name":"List requested jurisdictions","request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/api/v1/jurisdictions/requests","host":["{{base_url}}"],"path":["api","v1","jurisdictions","requests"],"variable":[]},"description":"Public endpoint showing jurisdictions requested by developers, ranked by demand."},"response":[]},{"name":"Get jurisdiction statistics","request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/api/v1/jurisdictions/:slug/stats","host":["{{base_url}}"],"path":["api","v1","jurisdictions",":slug","stats"],"variable":[{"key":"slug","value":""}]},"description":"Returns permit counts and processing time data for a specific jurisdiction."},"response":[]},{"name":"Get jurisdiction analytics","request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/api/v1/jurisdictions/:slug/analytics","host":["{{base_url}}"],"path":["api","v1","jurisdictions",":slug","analytics"],"variable":[{"key":"slug","value":""}]},"description":"Returns processing time norms, permit counts, and type breakdowns for a jurisdiction."},"response":[]},{"name":"Request a new jurisdiction","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"url":{"raw":"{{base_url}}/api/v1/jurisdictions/request","host":["{{base_url}}"],"path":["api","v1","jurisdictions","request"],"variable":[]},"description":"Request SignedOff to add support for a new jurisdiction. Existing requests are upvoted.","body":{"mode":"raw","raw":"{\n  \"// see API docs for body schema\": true\n}","options":{"raw":{"language":"json"}}}},"response":[]},{"name":"Register a webhook","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"url":{"raw":"{{base_url}}/api/v1/webhooks","host":["{{base_url}}"],"path":["api","v1","webhooks"],"variable":[]},"description":"Subscribe to permit events via webhook. Active-webhook limits are per plan: Free 1, Developer 5, Pro 10, Enterprise 25.","body":{"mode":"raw","raw":"{\n  \"// see API docs for body schema\": true\n}","options":{"raw":{"language":"json"}}}},"response":[]},{"name":"List webhooks","request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/api/v1/webhooks","host":["{{base_url}}"],"path":["api","v1","webhooks"],"variable":[]},"description":"List all webhooks for the authenticated API key."},"response":[]},{"name":"Deactivate a webhook","request":{"method":"DELETE","header":[],"url":{"raw":"{{base_url}}/api/v1/webhooks/:webhook_id","host":["{{base_url}}"],"path":["api","v1","webhooks",":webhook_id"],"variable":[{"key":"webhook_id","value":""}]},"description":"Soft-deactivate a webhook. Only the owning API key can delete."},"response":[]},{"name":"Update a webhook","request":{"method":"PATCH","header":[{"key":"Content-Type","value":"application/json"}],"url":{"raw":"{{base_url}}/api/v1/webhooks/:webhook_id","host":["{{base_url}}"],"path":["api","v1","webhooks",":webhook_id"],"variable":[{"key":"webhook_id","value":""}]},"description":"Change URL, events, jurisdiction filter, or active state. Reactivating a webhook resets its failure counter.","body":{"mode":"raw","raw":"{\n  \"// see API docs for body schema\": true\n}","options":{"raw":{"language":"json"}}}},"response":[]},{"name":"List recent delivery attempts","request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/api/v1/webhooks/:webhook_id/deliveries","host":["{{base_url}}"],"path":["api","v1","webhooks",":webhook_id","deliveries"],"variable":[{"key":"webhook_id","value":""}]},"description":"Delivery history for a webhook — status, attempts, and the last error per event. Newest first."},"response":[]},{"name":"Rotate the signing secret","request":{"method":"POST","header":[],"url":{"raw":"{{base_url}}/api/v1/webhooks/:webhook_id/rotate-secret","host":["{{base_url}}"],"path":["api","v1","webhooks",":webhook_id","rotate-secret"],"variable":[{"key":"webhook_id","value":""}]},"description":"Generates a new whsec_ secret and returns it once. Deliveries sign with the new secret immediately — update your receiver first."},"response":[]},{"name":"Send a test webhook event","request":{"method":"POST","header":[],"url":{"raw":"{{base_url}}/api/v1/webhooks/:webhook_id/test","host":["{{base_url}}"],"path":["api","v1","webhooks",":webhook_id","test"],"variable":[{"key":"webhook_id","value":""}]},"description":"Sends a sample status_change event to the webhook URL and returns the delivery result."},"response":[]},{"name":"Simulate a status_change event","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"}],"url":{"raw":"{{base_url}}/api/v1/webhooks/:webhook_id/simulate","host":["{{base_url}}"],"path":["api","v1","webhooks",":webhook_id","simulate"],"variable":[{"key":"webhook_id","value":""}]},"description":"POSTs a synthetic status_change (or other valid event) payload — same canonical shape as a production webhook — to your registered URL so you can verify your receiver before any live event fires. The request body is optional; omitting it simulates a 'status_change' event. Returns the upstream status_code and a body preview.","body":{"mode":"raw","raw":"{\n  \"// see API docs for body schema\": true\n}","options":{"raw":{"language":"json"}}}},"response":[]},{"name":"Download Postman v2.1 collection","request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/api/v1/postman.json","host":["{{base_url}}"],"path":["api","v1","postman.json"],"variable":[]},"description":"Returns the complete public API as a Postman v2.1 collection — one-click import in Postman. Auth is pre-wired with X-API-Key; set the api_key collection variable to your key after import."},"response":[]},{"name":"Get key & plan info","request":{"method":"GET","header":[],"url":{"raw":"{{base_url}}/api/v1/me","host":["{{base_url}}"],"path":["api","v1","me"],"variable":[]},"description":"Returns the authenticated key's plan, monthly credit limit, webhook limit, and current active-webhook count. Integrations (e.g. Zapier) use this to validate the key on connect and surface plan limits. Does not consume a credit and is not rate-limited."},"response":[]}]}