Webhooks

Receive real-time notifications for payment events, tenant screening results, and other platform activities.

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.

EventDescription
transaction.completedA payment has been successfully processed
transaction.failedA payment attempt has failed
transaction.refundedA payment has been refunded to the payer
recurring.processedA recurring payment has been automatically processed
chargeback.createA chargeback has been filed against a transaction
chargeback.updateA chargeback status has been updated (Won, Lost, Processed)
boardingApplication.statusChangedMerchant 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.

Verify Webhook Signature (Node.js)
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

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

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

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

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.

EventDescription
screening.completedScreening report is ready for review
screening.pendingScreening has been initiated and is in progress
screening.failedScreening 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:

AttemptDelay
1st retry1 minute
2nd retry5 minutes
3rd retry30 minutes
4th retry2 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 TypeDescription
payment.createdNew payment record created
payment.succeededPayment completed successfully
payment.failedPayment declined or failed
payment.refundedPayment refunded or ACH returned
rent.overdue_noticeOverdue notice sent (includes tier: 1/5/15/30 days)
autopay.enrolledTenant enrolled in autopay
autopay.failedAutopay payment attempt failed
autopay.reminder_sentEnrollment reminder sent to tenant
lease.expiringLease expiration alert triggered