Developers
Integrate in a day.
Verify in an hour.
Signed requests in, signed events out. No SDK required on the server side — it is HTTP and an HMAC you already know how to check.
Event contract
What lands on your endpoint
Your LMS is the system of record; our stream is the narrative. When the two disagree, fetch the case — the snapshot is authoritative.

Append only
A record, not a report
Sequenced per account, signed over a timestamped body, replayable after an outage. A gap is visible rather than silent.
Check the signature
The timestamp is inside the MAC, so a captured payload cannot be replayed later. Tolerance is five minutes.
// headers
// X-TapProof-Timestamp: 1804393800
// X-TapProof-Signature: v1=<hex>
// X-TapProof-Sequence: 42
const expected = crypto
.createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
// constant-time, always
const ok = crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected),
);Take a payment
An ActivityResultContract, so you get process-death and configuration-change safety for free — which matters on the handsets a field fleet actually carries.
TapProof.initialize(this, TapProofConfig(
baseUrl = "https://api.tapproof.in",
environment = PRODUCTION,
tokenProvider = { authStore.freshToken() },
certificatePins = listOf("…"), // required in prod
))
val collect = rememberLauncherForActivityResult(
TapProofContract()
) { result -> handle(result) }
collect.launch(CollectRequest(amountPaise = 250_000))
Refusals are events too
You are told what did not happen, and why
Every blocked contact arrives with a reason code. Most platforms drop these on the floor; they are the half that proves your operation was run properly.
Guarantees
Four properties you can build against

Idempotent

Sequenced
Absolute
Replayable
Verification
The timestamp is inside the signature
Which means a payload captured off the wire cannot be replayed at you later. Tolerance is five minutes; anything older is rejected before it reaches your handler.
Compare in constant time. We publish working verification code rather than a description of it, because a description is where most webhook integrations go wrong.

HMAC-SHA256 over timestamp + raw body
Run it yourself
A demo that needs no infrastructure
The whole flow — refusals included — runs on a laptop with no database, no Redis and no network. Point your integration engineer at it before a single call is scheduled.
$ node scripts/demo.js
02 Assignment — eligibility is checked before a name reaches the customer
[--] FP-DEL-0912 refused — agent_certificate_expired
[ok] FP-DEL-0417 assigned — IIBF valid, antecedents clear
04 The contact window is enforced, not reported on
[--] 19:40 IST refused — outside_contact_window
[--] one hour's notice refused — notice_less_than_one_day
[ok] 12:00 IST, two days' notice — visit opens
08 Outcome returns as a signed, sequenced, verifiable event
[ok] your endpoint verifies the signature
[ok] tampered payload rejected — signature_mismatch
[ok] replay an hour later rejected — timestamp_outside_tolerance