Skip to main content
Your webhook URL is public, so anything on the internet can post to it. Never credit a customer, release goods, or mark an order paid until you have verified the event. There are two ways to check, and they work well together.
Treat an unverified webhook as untrusted input. A forged “deposit” event that your code trusts is a direct path to losing money.

Signature validation

Every event Pila sends carries an x-pila-signature header. Its value is an HMAC SHA256 signature of the event payload, signed with your secret key. Recompute the signature over the raw request body and compare it to the header before doing anything else.
Compare with a constant-time function — crypto.timingSafeEqual, hmac.compare_digest, hash_equals — rather than ==. A plain comparison leaks timing information an attacker can use to guess the signature.

IP allowlisting

You can also restrict your webhook endpoint so only Pila can reach it. Pila sends webhooks from a single address:
Allow that address at your firewall, load balancer, or in application middleware, and reject everything else.
IP allowlisting is a useful second layer, but it is not a substitute for signature validation. Verify the signature even if the request came from the right address.

Responding to events

1

Verify first

Check the signature before parsing or acting on the payload.
2

Reply 200 quickly

Acknowledge the event, then do the slow work — database writes, emails, ledger updates — in a background job. A slow endpoint looks like a failed one.
3

Handle duplicates

The same event can arrive more than once. Key your processing on the transaction or event identifier so a repeat delivery is a no-op.
4

Log without PII

Record the event type, identifier and outcome. Do not log full payloads — they contain names, phone numbers and account details.

Next

Subscribe to webhooks

Register the URL that will receive these events.

Card events

Every card event payload, field by field.