Skip to content

Beds24 thread reconciliation

runBeds24MessageReconciliation in src/lib/beds24-reconciliation.ts. Runs every 15 min, before the watchdog, to keep beds24_messages.verified_in_thread_at + outbound_log.delivered_at up to date.

Why this exists

Mailgun and Twilio both have webhooks that fire when delivery completes. Beds24 doesn’t. The closest signal is “is the message in the thread when you GET it later?”

Without reconciliation, every Beds24 thread message would stay in the watchdog’s “stale, no delivery confirmation” pile forever.

What it does

  1. Find unverified beds24_messages rows from the last 24h:
    SELECT id, booking_id, beds24_message_id
    FROM beds24_messages
    WHERE verified_in_thread_at IS NULL
    AND sent_at >= ?
  2. Group by booking_id — one API call per booking covers all that booking’s pending verifications
  3. For each booking, fetch /bookings/messages?bookingId=X via Beds24 v2 API
  4. For each unverified row, check if the message-id is in the returned thread
  5. On match:
    • Set verified_in_thread_at on the beds24_messages row
    • Call markOutboundDelivered(env, "beds24_message", id, now) to update the outbound_log row

Bounds + failure handling

  • Only checks rows <24h old (older = no point re-fetching)
  • One booking’s API failure doesn’t block others (try/catch per booking)
  • If access token fetch fails, the whole sweep skips — try again next 15 min

Source

  • src/lib/beds24-reconciliation.ts
  • src/beds24/client.tsgetBookingMessages GET helper
  • migrations/0024_delivery_observability.sql (creates beds24_messages)
  • Tests: test/lib/beds24-reconciliation.test.ts (7 cases)