v4/Mosler Direct

Delivering 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

Configure a callback URL on your Integration in the Mosler client portal. When the worker finishes provisioning (or revoking) access, Mosler POSTs an authenticated 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, the credential for that type (passcode, cardId, or lockData + lockMac for e-keys), 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"
        },
        {
            "deviceName": "Room 101 Door",
            "roomNumber": "101",
            "bedNumber": null,
            "type": "ekey",
            "lockData": "Rz7oNSAH1No3YXRiG0j8FKB3xBjhuILrkTjWkOMw...",
            "lockMac": "AA:BB:CC:DD:EE:FF",
            "validFrom": "2025-08-01T08:30:00.000Z",
            "validUntil": "2025-08-05T05:30:00.000Z"
        }
    ]
}

E-key credentials arrive in full. For type: "ekey" the callback carries lockData and lockMac inline — everything the Mobile Key SDK needs. You do not have to call back to the API to complete an e-key.

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

By default, each call carries an X-Mosler-Signature header: an HMAC-SHA256 of the raw request body, keyed with the callback secret stored on your Integration. 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)
    );
}
Outbound auth options

HMAC signing is the default. On your Integration you can instead choose Bearer token, Basic auth, a custom API-key header, or none — Mosler attaches the configured credential to every callback (including the test.ping). Pick the scheme your endpoint expects when you set up the Integration in the client portal.

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.in/api/v4/callbacks/test \
  -H "apikey: YOUR_API_KEY"

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

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

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

Mode 1 is self-service: create an Integration in the Mosler client portal and set its callback URL, outbound auth scheme, and scope — then verify it end-to-end with POST /api/v4/callbacks/test. Mode 2 (direct guest messaging) channel preferences are configured per company/site in the Mosler Admin portal.