New and changed permits pushed to your endpoint about 60 seconds after we ingest them; most sources are ingested nightly. Developer plan ($79/mo) and above.
List all your registered webhooks.
import os
from permitstack import Permitstack
with Permitstack(
api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:
res = p_client.webhooks.list_webhooks()
# Handle response
print(res)
| Parameter |
Type |
Required |
Description |
retries |
Optional[utils.RetryConfig] |
➖ |
Configuration to override the default retry behavior of the client. |
Any
| Error Type |
Status Code |
Content Type |
| errors.ErrorDetail |
401, 429 |
application/json |
| errors.PermitstackDefaultError |
4XX, 5XX |
*/* |
Register a webhook to be notified when new permits match your filters.
Available on the Developer plan and above (see /v1/billing/plans for current
pricing). Maximum 10 webhooks per API key.
When a new permit matches your filters, we'll POST the permit data as JSON to your URL.
Set contractor_name to track a specific company — you'll get a POST within minutes
of any permit they pull appearing in our data (competitor tracking).
import os
from permitstack import Permitstack
with Permitstack(
api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:
res = p_client.webhooks.create_webhook(url="https://helpful-cafe.biz")
# Handle response
print(res)
| Parameter |
Type |
Required |
Description |
url |
str |
✔️ |
N/A |
city |
OptionalNullable[str] |
➖ |
N/A |
state |
OptionalNullable[str] |
➖ |
N/A |
category |
OptionalNullable[str] |
➖ |
N/A |
zip_code |
OptionalNullable[str] |
➖ |
N/A |
keyword |
OptionalNullable[str] |
➖ |
N/A |
contractor_name |
OptionalNullable[str] |
➖ |
Fire only for permits pulled by contractors whose name contains this text (case-insensitive) — track a competitor or partner as their new permits arrive. |
retries |
Optional[utils.RetryConfig] |
➖ |
Configuration to override the default retry behavior of the client. |
Any
| Error Type |
Status Code |
Content Type |
| errors.FeatureLockedError |
403 |
application/json |
| errors.HTTPValidationError |
422 |
application/json |
| errors.ErrorDetail |
401, 429 |
application/json |
| errors.PermitstackDefaultError |
4XX, 5XX |
*/* |
Delete a webhook.
import os
from permitstack import Permitstack
with Permitstack(
api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:
res = p_client.webhooks.delete_webhook(webhook_id="<id>")
# Handle response
print(res)
| Parameter |
Type |
Required |
Description |
webhook_id |
str |
✔️ |
N/A |
retries |
Optional[utils.RetryConfig] |
➖ |
Configuration to override the default retry behavior of the client. |
Any
| Error Type |
Status Code |
Content Type |
| errors.HTTPValidationError |
422 |
application/json |
| errors.ErrorDetail |
401, 429 |
application/json |
| errors.PermitstackDefaultError |
4XX, 5XX |
*/* |
Re-activate (or deactivate) one of your webhooks.
Re-activating resumes delivery from now: permits ingested while the webhook was paused
are not replayed (use /v1/permits/search or /v1/permits/sync to backfill a gap), so a
newly fixed endpoint is not hit with the whole backlog at once. The failure count resets
to zero.
import os
from permitstack import Permitstack
with Permitstack(
api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:
res = p_client.webhooks.update_webhook(webhook_id="<id>", is_active=True)
# Handle response
print(res)
| Parameter |
Type |
Required |
Description |
webhook_id |
str |
✔️ |
N/A |
is_active |
bool |
✔️ |
true re-activates a webhook the failure breaker switched off. |
retries |
Optional[utils.RetryConfig] |
➖ |
Configuration to override the default retry behavior of the client. |
Any
| Error Type |
Status Code |
Content Type |
| errors.HTTPValidationError |
422 |
application/json |
| errors.ErrorDetail |
401, 429 |
application/json |
| errors.PermitstackDefaultError |
4XX, 5XX |
*/* |
Send a test event to a webhook URL.
Useful for verifying your webhook endpoint is reachable and signature
validation works. Sends a fake permit payload with event=permit.test.
import os
from permitstack import Permitstack
with Permitstack(
api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:
res = p_client.webhooks.test_webhook(webhook_id="<id>")
# Handle response
print(res)
| Parameter |
Type |
Required |
Description |
webhook_id |
str |
✔️ |
N/A |
retries |
Optional[utils.RetryConfig] |
➖ |
Configuration to override the default retry behavior of the client. |
Any
| Error Type |
Status Code |
Content Type |
| errors.HTTPValidationError |
422 |
application/json |
| errors.ErrorDetail |
401, 429 |
application/json |
| errors.PermitstackDefaultError |
4XX, 5XX |
*/* |
Why your webhook is or is not being delivered, seen from our side of the connection.
Only FAILED attempts are recorded individually; successful deliveries are counted
(fire_count, last_fired_at). An empty recent_failures list is therefore good news, not
missing data. consecutive_failures is what the automatic pause acts on: when it reaches
the limit the webhook is deactivated, so it is the field to watch.
import os
from permitstack import Permitstack
with Permitstack(
api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:
res = p_client.webhooks.get_webhook_deliveries(webhook_id="<id>", limit=20)
# Handle response
print(res)
| Parameter |
Type |
Required |
Description |
webhook_id |
str |
✔️ |
N/A |
limit |
Optional[int] |
➖ |
How many recent failed attempts to return. |
retries |
Optional[utils.RetryConfig] |
➖ |
Configuration to override the default retry behavior of the client. |
Any
| Error Type |
Status Code |
Content Type |
| errors.HTTPValidationError |
422 |
application/json |
| errors.ErrorDetail |
401, 429 |
application/json |
| errors.PermitstackDefaultError |
4XX, 5XX |
*/* |
Issue a NEW signing secret for this webhook. The old one stops working immediately.
Every delivery after this call is signed with the new secret, so update your verifier
first. Creating a webhook again with the same settings returns the existing secret; this
endpoint is the only way to rotate it.
import os
from permitstack import Permitstack
with Permitstack(
api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:
res = p_client.webhooks.rotate_webhook_secret(webhook_id="<id>")
# Handle response
print(res)
| Parameter |
Type |
Required |
Description |
webhook_id |
str |
✔️ |
N/A |
retries |
Optional[utils.RetryConfig] |
➖ |
Configuration to override the default retry behavior of the client. |
Any
| Error Type |
Status Code |
Content Type |
| errors.HTTPValidationError |
422 |
application/json |
| errors.ErrorDetail |
401, 429 |
application/json |
| errors.PermitstackDefaultError |
4XX, 5XX |
*/* |
Retrieve your webhook signing secret. Use this to validate signatures.
The X-PermitStack-Signature header on incoming webhook requests is the
HMAC-SHA256 of the request body using this secret. Verify before
processing to ensure the request came from PermitStack.
import os
from permitstack import Permitstack
with Permitstack(
api_key=os.getenv("PERMITSTACK_API_KEY", ""),
) as p_client:
res = p_client.webhooks.get_webhook_secret(webhook_id="<id>")
# Handle response
print(res)
| Parameter |
Type |
Required |
Description |
webhook_id |
str |
✔️ |
N/A |
retries |
Optional[utils.RetryConfig] |
➖ |
Configuration to override the default retry behavior of the client. |
Any
| Error Type |
Status Code |
Content Type |
| errors.HTTPValidationError |
422 |
application/json |
| errors.ErrorDetail |
401, 429 |
application/json |
| errors.PermitstackDefaultError |
4XX, 5XX |
*/* |