Webhooks
Webhooks let Proxiant notify your systems when events happen — no polling required. When a job is served, an affidavit is generated, or a server accepts a Hive job, we POST a JSON payload to your endpoint immediately.
Overview
X-Proxiant-SignatureYour endpoint must respond with a 2xx status code within 10 seconds to acknowledge delivery. If it doesn't, Proxiant will retry. After all retries are exhausted, the webhook delivery is marked failed and the last_delivery_status on the webhook object is updated.
id field to deduplicate deliveries.List Webhooks
Returns all webhook subscriptions for your firm.
curl https://api.proxiant.co/v1/webhooks \ -H "Authorization: Bearer prx_live_xxxxxxxxxxxx"
{ "data": [ { "id": "wh_abc123-1111-2222-3333-444455556666", "url": "https://app.example.com/webhooks/proxiant", "events": ["job.served", "attempt.logged"], "active": true, "created_at": "2025-03-01T12:00:00Z", "last_delivery_at": "2025-04-15T09:22:11Z", "last_delivery_status": "success" } ] }
Create Webhook
Creates a new webhook subscription. Your endpoint will be called immediately with a webhook.test ping event upon creation.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| url | string | required | HTTPS endpoint to deliver events to |
| events | array | required | Array of event names to subscribe to |
| secret | string | optional | Secret for HMAC signature verification. Strongly recommended. |
curl -X POST https://api.proxiant.co/v1/webhooks \ -H "Authorization: Bearer prx_live_xxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "url": "https://app.example.com/webhooks/proxiant", "events": ["job.served", "job.non_est", "attempt.logged", "affidavit.generated"], "secret": "whsec_your_signing_secret_here" }'
Delete Webhook
Deletes a webhook subscription. Event delivery to this URL stops immediately.
curl -X DELETE https://api.proxiant.co/v1/webhooks/wh_abc123-1111-2222-3333-444455556666 \ -H "Authorization: Bearer prx_live_xxxxxxxxxxxx"
Returns 204 No Content on success.
Event Catalog
Subscribe to any combination of these events when creating a webhook. You can use "events": ["*"] to subscribe to all events.
| Event | Triggered when | Payload includes |
|---|---|---|
| job.created Jobs | A new job is created in your firm | Full job object |
| job.updated Jobs | Job fields or status changes | Job object + changed_fields array |
| job.served Jobs | Job is marked as successfully served | Job object + serving attempt object |
| job.non_est Jobs | Job is marked non-est (unable to serve) | Job object |
| job.overdue Jobs | Job passes its due date without being served | Job object |
| attempt.logged Attempts | A new service attempt is logged | Attempt object + parent job object |
| invoice.created Billing | An invoice is generated for a client | Invoice object |
| invoice.paid Billing | An invoice payment is recorded | Invoice object + payment object |
| affidavit.generated Affidavits | An affidavit PDF is generated and ready | Affidavit object + job object |
| hive.job_posted The Hive | A job is posted to The Hive marketplace | Job object |
| hive.job_accepted The Hive | A server accepts a job from The Hive | Job object + server object |
| eservice.accepted eService | Recipient accepts electronic service | Job object + eservice object |
Signature Verification
When you provide a secret when creating a webhook, Proxiant signs every delivery with an X-Proxiant-Signature header. This lets you verify that the request actually came from Proxiant and wasn't tampered with.
The signature is computed as: HMAC-SHA256(raw_request_body, secret), hex-encoded, prefixed with sha256=.
const crypto = require('crypto'); function verifyWebhook(rawBody, signature, secret) { const expectedSig = 'sha256=' + crypto.createHmac('sha256', secret) .update(rawBody) .digest('hex'); // Timing-safe comparison prevents timing attacks return crypto.timingSafeEqual( Buffer.from(expectedSig), Buffer.from(signature) ); } // Express example app.post('/webhooks/proxiant', express.raw({ type: 'application/json' }), (req, res) => { const sig = req.headers['x-proxiant-signature']; if (!verifyWebhook(req.body, sig, process.env.FINALHIVE_WEBHOOK_SECRET)) { return res.status(401).send('Invalid signature'); } const event = JSON.parse(req.body); // Handle event... res.status(200).json({ received: true }); });
import hmac, hashlib, os def verify_webhook(raw_body: bytes, signature: str, secret: str) -> bool: expected = "sha256=" + hmac.new( secret.encode(), raw_body, hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, signature) # Flask example @app.route("/webhooks/proxiant", methods=["POST"]) def webhook(): sig = request.headers.get("X-Proxiant-Signature", "") if not verify_webhook(request.get_data(), sig, os.environ["FINALHIVE_WEBHOOK_SECRET"]): return "Invalid signature", 401 event = request.get_json() # Handle event... return {"received": True}, 200
Example Payload
Every event delivery includes a standard envelope with the event type, ID, timestamp, and the event-specific data.
job.served
{ "id": "evt_7f3a9b12-cdef-4567-89ab-cdef01234567", "event": "job.served", "created_at": "2025-04-15T09:22:15Z", "data": { "job": { "id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d", "job_number": "FH-2025-04812", "status": "served", "job_type": "subpoena", "recipient_name": "James R. Thornton", "client_id": "a3c4e5f6-1a2b-3c4d-5e6f-7g8h9i0j1k2l", "client_name": "Harmon & Keyes LLP", "updated_at": "2025-04-15T09:22:11Z" }, "attempt": { "id": "b2c3d4e5-2222-3333-4444-555566667777", "sequence_number": 3, "outcome": "served", "attempted_at": "2025-04-15T09:12:00Z", "gps_verified": true, "server_name": "Marcus Webb", "narrative": "Subject answered door, confirmed identity. Documents delivered in hand." } } }