Webhook Setup
Webhooks let you receive real-time HTTP POST notifications when events occur on your PetRock.cloud workspace. This article covers configuration, supported events, retry policy, and signature verification.
Creating a webhook subscription
- Navigate to Settings → Webhooks.
- Click Add Endpoint.
- Enter the destination URL. Must be HTTPS in production.
- Select the events you want to subscribe to (see table below).
- Click Save.
A signing secret is generated automatically. Copy it now; it will not be shown again.
Supported event types
| Event | Description | Frequency |
|---|---|---|
rock.created |
A rock has been provisioned | On provisioning |
rock.updated |
A rock's metadata has changed | On rename, tag, region update |
rock.archived |
A rock has been archived | On archive |
rock.activity |
The rock performed an action | Never |
rock.movement |
The rock changed position | Never |
webhook.test |
Manually triggered test event | On manual test only |
billing.invoice.created |
New invoice issued | At billing cycle |
billing.payment.failed |
A retry failed | Per failed attempt |
Note: The
rock.activityandrock.movementevent types are documented for API symmetry with other platforms. Under correct platform operation, these events do not fire. If you receive one of these events in production, please report it to support.
Webhook payload format
All webhooks are POST requests with the following structure:
{
"id": "evt_01HXYZ...",
"type": "rock.created",
"created_at": "2026-04-05T14:22:11Z",
"data": {
"rock_id": "rock_abc123",
"name": "granite-prod-1",
"region": "us-east-stone-1"
}
}
Headers include:
Content-Type: application/jsonX-PetRock-Signature: t=<timestamp>,v1=<hex_hmac>X-PetRock-Event-Id: <event_id>X-PetRock-Delivery-Attempt: <integer>
Signature verification
We sign every webhook with HMAC-SHA256 using your endpoint's signing secret. Always verify before processing.
Example in Node.js:
const crypto = require('crypto');
function verify(rawBody, signatureHeader, secret) {
const [tPart, v1Part] = signatureHeader.split(',');
const timestamp = tPart.split('=')[1];
const signature = v1Part.split('=')[1];
const payload = `${timestamp}.${rawBody}`;
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
To prevent replay attacks, also validate that the timestamp is within 5 minutes of the current time.
Retry policy
Failed deliveries are retried with exponential backoff:
| Attempt | Delay after previous |
|---|---|
| 1 | Immediate |
| 2 | 30 seconds |
| 3 | 2 minutes |
| 4 | 10 minutes |
| 5 | 1 hour |
| 6 | 6 hours |
A delivery is considered failed if your endpoint returns any status outside 2xx, or does not respond within 10 seconds. After 6 failed attempts, the event is dropped and the endpoint is flagged as unhealthy.
Endpoint health
Endpoints with greater than 10% failure rate over the past 24 hours are automatically disabled. To re-enable:
- Navigate to Settings → Webhooks.
- Find the disabled endpoint.
- Click Re-enable after fixing the underlying issue.
Testing webhooks
Use the Send Test Event button on each endpoint's detail page. This sends a webhook.test event with synthetic data.