PIING
Reading IntegrationsWebhooks and custom integrations
Integrations
- Connect Piing to your stack
- Connect Shopify
- What Piing reads back from your stack
- Connect Klaviyo
- Connect Attentive
- Connect Rivo
- Connect Yotpo
- Connect LoyaltyLion
- Connect Antavo
- Connect Swym Wishlist Plus
- Award points on check-in
- Webhooks and custom integrations
In this guide
- The current event catalogue
- The payload
- Verify the signature
- Delivery, retry and replay
- Set up a destination
- If something looks wrong
Search or browse documentation
Integrations 12 / 12
Webhooks and custom integrations
Route selected Piing events to an HTTPS endpoint, verify the signed payload, monitor delivery and replay failures.
Use a webhook destination when a system does not have a native Piing connector or when you want to route events through your own integration layer. Add an HTTPS endpoint, choose the event types it should receive and Piing sends the same typed event envelope used by the rest of the routing system.
The current event catalogue
Recognition and identity
piing.checkin.created
piing.checkin.voided
piing.tap.seen
piing.checkin.duplicate_blocked
piing.tap.signup_redirect
piing.customer.created
piing.wallet.installed
piing.member.joined
Loyalty and visits
piing.points.earned
piing.points.adjusted
piing.visit.milestone
piing.store.unique_visit
piing.reward.redeemed
Outcomes and orders
piing.purchase.attributed
piing.checkin.no_purchase
piing.wishlist.converted
shopify.order.paid
shopify.order.fulfilled
The merchant chooses which destinations receive each event. Raw taps and blocked duplicates can be useful operationally, while accepted check-ins, purchases and no-purchase outcomes are usually the clearest inputs for customer journeys.
See the event documentation for the purpose and fields carried by each type.
The payload
A webhook request has a consistent JSON envelope. The properties object changes with the event type.
event_id is stable across automatic retries and can be used as an idempotency key. customer_id is null when the event has no resolved customer.
Verify the signature
Piing signs the exact raw JSON body with the per-destination signing secret and sends two headers:
To verify a delivery:
- Read the raw request body before parsing or re-serialising it.
- Compute the hexadecimal HMAC-SHA256 of those exact bytes using the signing secret.
- Prefix the result with
sha256= and compare it with X-Piing-Signature using a timing-safe comparison.
- Reject an old
X-Piing-Timestamp according to your replay tolerance. Five minutes is a practical default.
- Process each
event_id once.
The timestamp header changes on a retry, while the body and its signature remain stable. Keep the signing secret server-side and rotate it if it is exposed.
Delivery, retry and replay
Piing sends one request per subscribed event. A successful 2xx response marks the delivery complete. Retryable failures use exponential back-off with jitter, beginning at roughly one minute and moving through longer intervals, with up to six attempts by default. A non-retryable response or an exhausted delivery is left for inspection rather than silently discarded.
Return a 2xx response quickly, then move slower processing behind your own queue. The delivery log records the destination, event, status and response details needed to diagnose a failure. Failed deliveries can be replayed from that log.
Set up a destination
- Build an HTTPS endpoint that accepts a JSON
POST and preserves the raw body for verification.
- In Piing, open Integrations, add a webhook destination and enter the endpoint URL.
- Save the destination so Piing can create its signing secret.
- Choose the event types that should route to it.
- Send a test event and confirm the endpoint verifies the signature and returns
2xx.
- Monitor the first live deliveries before relying on the route for a customer journey.
For a non-Shopify implementation, the same route can be scoped through Retail ID.
If something looks wrong
- Signature mismatch. Hash the exact raw body, include the
sha256= prefix and confirm the destination is using its current secret.
- Timestamp rejected. Check the receiving server's clock and the replay tolerance.
- Duplicate processing. Store the stable
event_id and make the handler idempotent.
- Missing events. Confirm the event type is enabled for that destination and inspect its delivery log.
- Repeated retries. Return
2xx before doing slow work and check whether the response is classed as retryable.
Need a route that is not represented by the current native connectors? Contact us with the system, events, identity key and outcome you need to support.
Related guides
Was this guide helpful?
You’ve reached the end of Integrations.
Still need a hand? Contact us