Docs · Webhooks

Webhooks — Suite Profit

Suite Profit emits webhooks for every material portfolio event — a governed rate decision, a guest thread escalation, a reputation score drop, a parity breach, a fiscal batch approval, or an SSO provisioning change. Subscribe once per portfolio; deliveries are HMAC-SHA256 signed and mirrored to a secondary URL on Enterprise plans.

Subscribing

Create a subscription with a POST to /webhooks, scoped to a portfolio. You provide a primary URL (must be HTTPS), an optional secondary URL for Enterprise mirroring, an array of event types, and a description. We return a subscription ID and a per-portfolio signing secret. The secret is shown once — store it before the response window closes.

curl -X POST https://api.suiteprofit.org/v2/webhooks \
  -H "Authorization: Bearer sp_live_portfolio_47b91cb3..." \
  -H "X-SuiteProfit-Portfolio: prt_motlawa_estates" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://ops.motlawa-estates.example/webhooks/suiteprofit",
    "mirror_url": "https://siem.motlawa-estates.example/webhooks/mirror",
    "events": ["rate.decision.published", "parity.breach.detected", "fiscal.batch.approved"],
    "description": "Portfolio ops pipeline"
  }'

Event types

EventDescription
rate.decision.publishedA governed rate decision was published and written to Profitroom Suite across one or more properties.
rate.decision.revertedA previously published rate decision was reverted; audit trail records the reason and approver.
guest.thread.escalatedA cross-property guest conversation crossed the escalation threshold for portfolio ops.
reputation.score.droppedPortfolio-level reputation score dropped past the configured brand ceiling.
parity.breach.detectedOTA parity breach detected against the approved rate floor for a property.
fiscal.batch.approvedA fiscal batch (KSeF / FA(2)) was approved by the finance operator and submitted upstream.
operations.task.escalatedAn operations task escalated past its SLA tier; routed to the on-call rota.
sso.user.provisionedA user was provisioned into the portfolio via SCIM or SAML JIT.
sso.user.deprovisionedA user was deprovisioned; all per-property tokens issued to that principal are revoked.

Payload shape

Every payload is JSON. The top-level envelope is stable across event types and always carries the portfolio ID:

{
  "id": "evt_2b7d1c8a19f4",
  "type": "rate.decision.published",
  "created_at": "2026-07-28T09:12:44Z",
  "delivery_id": "del_a92c81",
  "portfolio_id": "prt_motlawa_estates",
  "properties": ["prop_gdansk_marina", "prop_sopot_grand"],
  "data": {
    "decision_id": "rdc_a19f4b7d",
    "room_type_code": "STDD",
    "date_range": { "from": "2026-08-14", "to": "2026-08-21" },
    "approver_saml_subject": "revenue.director@motlawa.example",
    "brand_ceiling_id": "brk_marina_flag"
  }
}

HMAC signature

Every delivery is signed with HMAC-SHA256 over the raw request body, using the per-portfolio signing secret. The signature ships in X-SuiteProfit-Signature as a hex string, alongside X-SuiteProfit-Portfolio. Verify by recomputing HMAC on the raw body — not the parsed JSON — and comparing constant-time.

// Node example
const crypto = require('crypto');
const expected = crypto
  .createHmac('sha256', process.env.SP_WEBHOOK_SECRET)
  .update(rawBody)
  .digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sigHeader))) {
  return res.status(401).end();
}

Delivery SLA and retry policy

At-least-once. A delivery is considered successful when your endpoint returns HTTP 2xx within 15 seconds. Failures retry with exponential backoff over 24 hours: at 1 min, 5 min, 15 min, 1h, 4h, 12h, 24h. Enterprise plans carry a 99.95% delivery SLA measured on the primary URL and receive SLA credit when the SLA is missed by more than 0.05%. Failed events land in a dead-letter queue that operators can replay for up to 90 days.

Enterprise webhook mirroring

Enterprise plans can register a mirror_url that receives an identical copy of every delivery. The mirror URL is typically pointed at a SIEM ingest endpoint (Splunk HEC, Elastic, or an S3+SQS bridge) and joins the enterprise audit stream. Mirror failures do not affect primary delivery accounting; the primary URL is the SLA-bearing target.

Per-endpoint throughput

We will not deliver more than 80 events per second per primary URL on Enterprise (20/s on Group, 5/s on Chain Starter). Excess is queued rather than dropped. Portfolios that need more can split events across multiple subscriptions with disjoint event filters.

Testing

Every subscription supports a POST /webhooks/{id}/ping that emits a synthetic webhook.ping event. Use it to verify signing and mirror wiring before enabling production events.