Overview
DoorStax dispatches webhooks for key events from integrated payment and screening providers. Webhooks are sent as HTTP POST requests with JSON payloads to your configured endpoint.
Kadima Payment Events
Payment events are dispatched by the Kadima payment processor and forwarded to your webhook endpoint.
| Event | Description |
|---|---|
| transaction.completed | A payment has been successfully processed |
| transaction.failed | A payment attempt has failed |
| transaction.refunded | A payment has been refunded to the payer |
| recurring.processed | A recurring payment has been automatically processed |
| chargeback.create | A chargeback has been filed against a transaction |
| chargeback.update | A chargeback status has been updated (Won, Lost, Processed) |
| boardingApplication.statusChanged | Merchant boarding application status changed (Approved, Declined, etc.) |
Signature Verification
All webhook payloads are signed using HMAC-SHA256. The signature is sent in the x-kadima-signature header. Always verify signatures before processing webhooks.
import crypto from "crypto";
function verifyWebhookSignature(payload, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your webhook handler:
app.post("/webhooks/kadima", (req, res) => {
const signature = req.headers["x-kadima-signature"];
const isValid = verifyWebhookSignature(
JSON.stringify(req.body),
signature,
process.env.KADIMA_WEBHOOK_SECRET
);
if (!isValid) {
return res.status(401).json({ error: "Invalid signature" });
}
// Process the webhook event
const { event, data } = req.body;
// ...
res.status(200).json({ received: true });
});Example Payloads
transaction.completed
{
"event": "transaction.completed",
"timestamp": "2025-01-15T14:30:00.000Z",
"data": {
"transactionId": "txn_abc123",
"amount": 150000,
"currency": "USD",
"status": "completed",
"paymentMethod": "ach",
"tenant": {
"id": "tnt_012",
"email": "tenant@example.com"
},
"lease": {
"id": "lea_xyz789",
"unitId": "unt_456"
},
"metadata": {
"description": "Rent payment - January 2025"
}
}
}transaction.failed
{
"event": "transaction.failed",
"timestamp": "2025-01-15T14:30:00.000Z",
"data": {
"transactionId": "txn_def456",
"amount": 150000,
"currency": "USD",
"status": "failed",
"failureReason": "insufficient_funds",
"failureCode": "R01",
"paymentMethod": "ach",
"tenant": {
"id": "tnt_012",
"email": "tenant@example.com"
},
"retryEligible": true,
"nextRetryAt": "2025-01-18T14:30:00.000Z"
}
}transaction.refunded
{
"event": "transaction.refunded",
"timestamp": "2025-01-20T10:00:00.000Z",
"data": {
"transactionId": "txn_abc123",
"refundId": "ref_ghi789",
"amount": 150000,
"currency": "USD",
"status": "refunded",
"reason": "duplicate_payment",
"initiatedBy": "usr_pm001"
}
}recurring.processed
{
"event": "recurring.processed",
"timestamp": "2025-02-01T06:00:00.000Z",
"data": {
"transactionId": "txn_rec001",
"recurringId": "rec_abc123",
"amount": 150000,
"currency": "USD",
"status": "completed",
"paymentMethod": "ach",
"schedule": {
"frequency": "monthly",
"dayOfMonth": 1,
"nextDate": "2025-03-01"
},
"tenant": {
"id": "tnt_012",
"email": "tenant@example.com"
}
}
}RentSpree Screening Webhooks
DoorStax integrates with RentSpree for tenant background screening. Screening results are delivered via webhooks when the screening is complete.
| Event | Description |
|---|---|
| screening.completed | Screening report is ready for review |
| screening.pending | Screening has been initiated and is in progress |
| screening.failed | Screening could not be completed |
Retry Policy
If your endpoint returns a non-2xx status code or times out (30 seconds), DoorStax will retry the webhook delivery with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
| 4th retry | 2 hours |
| 5th retry (final) | 24 hours |
Best Practice: Always return a 200 status code quickly and process the webhook asynchronously. This prevents timeouts and ensures reliable delivery.
DoorStax Internal Events
In addition to external webhooks, DoorStax tracks internal domain events via the DomainEvent model. These are used for deduplication, audit trails, and triggering downstream processes.
| Event Type | Description |
|---|---|
| payment.created | New payment record created |
| payment.succeeded | Payment completed successfully |
| payment.failed | Payment declined or failed |
| payment.refunded | Payment refunded or ACH returned |
| rent.overdue_notice | Overdue notice sent (includes tier: 1/5/15/30 days) |
| autopay.enrolled | Tenant enrolled in autopay |
| autopay.failed | Autopay payment attempt failed |
| autopay.reminder_sent | Enrollment reminder sent to tenant |
| lease.expiring | Lease expiration alert triggered |