v4/Mosler Direct

Delivering Access

Status: Planned (v4). Access delivery is being built. This page describes the intended design so you can plan your integration. Until it ships, retrieve credentials by polling — see Retrieving Access.

Retrieving Access is the pull model — you ask Mosler for a credential when you need it. Delivery is the push model — Mosler sends the credential to you, or directly to the guest, the moment provisioning finishes. No polling required.

There are two delivery modes; you can use either or both.


Mode 1 — Webhook event caller

Register a callback URL for your company/site. When the worker finishes provisioning (or revoking) access, Mosler POSTs a signed event to that URL. Your endpoint records the credential and replies 2xx.

Booking event COMPLETED
        │
        ▼
Mosler  ──POST {signed access.provisioned}──►  https://your-system/mosler/callback
        ◄────────────── 200 OK ──────────────
Event payload
FieldTypeDescription
schemaVersionnumberPayload contract version, currently 1. Pin or range-check this — new optional fields may be added under the same major.
eventstringaccess.provisioned, access.revoked, or access.failed
referenceIdstringYour booking reference
occurredAtstringISO 8601 UTC timestamp
bookingobject{ id, status, startDate, endDate }
access[]arraySame per-device shape as GET …/accesstype, passcode/cardId, device/room/bed, validity. Present on access.provisioned / access.revoked.
errorobjectOnly on access.failed: { code, message } describing why provisioning failed (e.g. gateway offline, no device bound, room mismatch). Replaces access[].
{
    "schemaVersion": 1,
    "event": "access.provisioned",
    "referenceId": "RES-20250718-001",
    "occurredAt": "2025-08-01T08:30:02.114Z",
    "booking": {
        "id": "6576fe78632cfff91c62a3c2",
        "status": "active",
        "startDate": "2025-08-01T08:30:00.000Z",
        "endDate": "2025-08-05T05:30:00.000Z"
    },
    "access": [
        {
            "deviceName": "Room 101 Door",
            "roomNumber": "101",
            "bedNumber": null,
            "type": "passcode",
            "passcode": "482910",
            "validFrom": "2025-08-01T08:30:00.000Z",
            "validUntil": "2025-08-05T05:30:00.000Z"
        }
    ]
}

An access.failed event carries an error object instead of access[]:

{
    "schemaVersion": 1,
    "event": "access.failed",
    "referenceId": "RES-20250718-001",
    "occurredAt": "2025-08-01T08:30:02.114Z",
    "booking": {
        "id": "6576fe78632cfff91c62a3c2",
        "status": "active",
        "startDate": "2025-08-01T08:30:00.000Z",
        "endDate": "2025-08-05T05:30:00.000Z"
    },
    "error": {
        "code": "NO_DEVICE_BOUND",
        "message": "No lock is mapped to room 101 at this site."
    }
}
Verifying the signature

Each call carries an X-Mosler-Signature header: an HMAC-SHA256 of the raw request body, keyed with the callback secret issued alongside your callback URL. Recompute it and compare before trusting the payload.

import crypto from 'crypto';

function isValid(rawBody, signatureHeader, secret) {
    const expected = crypto
        .createHmac('sha256', secret)
        .update(rawBody) // the exact bytes received
        .digest('hex');
    return crypto.timingSafeEqual(
        Buffer.from(expected),
        Buffer.from(signatureHeader)
    );
}
Delivery guarantees
  • Retries: non-2xx responses (and timeouts) are retried with exponential backoff. After the final attempt the event is dead-lettered and surfaced for manual replay.
  • Idempotency: retries reuse the same payload. De-duplicate on (referenceId, event, occurredAt) — your endpoint may receive a delivery more than once.
  • Ordering: not guaranteed under retries. Treat access.revoked as authoritative over an earlier access.provisioned for the same booking by comparing occurredAt.
Verifying your endpoint before go-live

Before you take a real booking, confirm your callback URL and signature check work end-to-end. Fire a signed test.ping at your registered URL:

POST /api/v4/callbacks/test

curl -X POST https://api.mosler.io/api/v4/callbacks/test \
  -H "apikey: YOUR_API_KEY"

Mosler delivers a test.ping event to your registered callback URL — signed with the same X-Mosler-Signature scheme as real events — and returns the HTTP result it observed from your endpoint:

{
    "delivered": true,
    "url": "https://your-system/mosler/callback",
    "responseStatus": 200,
    "signatureScheme": "hmac-sha256"
}

The test.ping body matches the standard envelope so your verifier exercises the real code path:

{
    "schemaVersion": 1,
    "event": "test.ping",
    "occurredAt": "2025-08-01T08:30:02.114Z",
    "message": "Mosler callback verification ping."
}

No booking is created. Use this to validate your endpoint and signature verification without touching a real reservation.


Mode 2 — Direct guest messaging

Let Mosler deliver the credential straight to the guest — no callback handling, no app on your side. When provisioning completes, Mosler sends the passcode (or a mobile-key link) to the guest over WhatsApp and/or email using Mosler templates.

To enable it, include guest contact details on the booking and the property's messaging preference is configured in the Mosler Admin portal:

{
  reference_id: "RES-20250718-001",
  action: "create",
  room_number: "101",
  guest: {
    name: "Jane Smith",
    email: "jane.smith@example.com",   // → email delivery
    phone: "+919991234567"             // → WhatsApp/SMS delivery
  },
  access_type: "PASSCODE"
}

The guest receives a Mosler-branded message with their PIN (or a link to open their mobile key) and the stay window. Revocation on checkout/cancel can likewise notify the guest that access has ended.


Choosing a mode

Webhook event callerDirect guest messaging
Who receives the credentialYour systemThe guest
You buildA callback endpointNothing — just send guest contact
Best whenYou own the guest experience/appYou want Mosler to handle delivery

You can combine them: receive the callback for your records and have Mosler message the guest.


Setup

Both modes are configured per company/site in the Mosler Admin portal — callback URL + secret for Mode 1, messaging channel preferences for Mode 2. Contact your Mosler representative to enable delivery for your account while this feature is rolling out.