Wow! Build your WhatsApp integration. Start free. Register Now
Hotel remote check-in · WhatsApp API use case

Reply with a WhatsApp door code after a guest ID upload

Guests finish remote check-in when the door access code arrives in the same chat after they send a passport or ID document. When that document lands on your hotel channel, your backend can retrieve the file, accept it against the booking, and send the code as ordinary chat text through Whapi.Cloud. This use case shows integrators how to implement that flow through the WhatsApp API.

Triggered by inbound document on messages.post Door code sent as chat text to the guest
Hotel laptop with a booking record beside a phone WhatsApp chat where a guest passport document sits above a door access code reply.
Use case

When to use this flow

The passport or ID arrives as a WhatsApp document

Use this flow when a booked guest sends the scan or photo as an inbound document on the property channel, not when staff still collect paper at the desk for every arrival.

The door code must wait for document acceptance

Use this flow when your backend should mint and send the access code only after the file is retrieved and matched to the booking — not a code sent before the ID is accepted.

Late or unattended arrivals still need access

Use this flow when the property must release a door code in chat for after-hours or remote check-in without keeping a full desk online for every arrival.

WhatsApp chat on a phone showing a guest passport document above a reply that contains the hotel door access code.
Customer experience

The guest gets the door code in chat

Before automation, the guest waits at the door or messages reception while someone finds the booking, checks the passport, and types an access code by hand — often after hours.

After the flow runs, the guest sees the door access code in the same WhatsApp chat where they sent the ID document. Integrators build this result with the WhatsApp API.

Workflow

From ID document to door code

1

Inbound guest document

The channel posts a messages.post webhook with type document (passport or ID). The payload carries document.id as MediaID, optional document.link when Auto Download is on, and the guest from / chat_id. Whapi.Cloud does not run your booking or lock logic.

2

Retrieve the uploaded ID file

GET /media/{MediaID}

getMedia downloads the file from cloud storage by MediaID so your backend can accept it against the booking. If Auto Download already exposed a usable link, you may fetch that URL instead, but this job still names the MediaID retrieve step.

3

Send the door access code

POST /messages/text

After own_backend accepts the document and mints the code, sendMessageText posts that code as ordinary text to the guest phone or chat id.

Need delivery tracking? A successful send response is not proof the guest already has the door code. Track later acks on delivery webhooks. Learn about delivery status →

Prerequisites

Before you run the flow

Connect the WhatsApp number that guests use for check-in documents, and authenticate every request with that number's API token. Booking matching, door-code minting, and reception alerts stay on your backend.

Optional — go deeper for this flow

API implementation

The calls that retrieve media and send the code

Your webhook already named the guest and the document MediaID. These calls retrieve that file, then deliver the door access code your backend minted after acceptance.

Get your API token for free after you register on whapi.cloud, and use that token in the code instead of Your_Token from the examples.

Retrieve the uploaded ID file

Download the guest passport or ID file by MediaID from the inbound document webhook so own_backend can accept it.

curl --request GET \
     --url https://gate.whapi.cloud/media/{MediaID} \
     --header 'accept: application/json' \
     --header 'authorization: Bearer Your_Token'
$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://gate.whapi.cloud/media/{MediaID}",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => [
    "accept: application/json",
    "authorization: Bearer Your_Token"
  ],
]);

$response = curl_exec($curl);
curl_close($curl);
echo $response;
import requests

url = "https://gate.whapi.cloud/media/{MediaID}"
headers = {
    "accept": "application/json",
    "authorization": "Bearer Your_Token"
}

response = requests.get(url, headers=headers)
print(response.content)
const response = await fetch('https://gate.whapi.cloud/media/{MediaID}', {
  method: 'GET',
  headers: {
    accept: 'application/json',
    authorization: 'Bearer Your_Token',
  },
});

console.log(await response.arrayBuffer());
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
  .url("https://gate.whapi.cloud/media/{MediaID}")
  .get()
  .addHeader("accept", "application/json")
  .addHeader("authorization", "Bearer Your_Token")
  .build();

Response response = client.newCall(request).execute();
using RestSharp;

var options = new RestClientOptions("https://gate.whapi.cloud/media/{MediaID}");
var client = new RestClient(options);
var request = new RestRequest("");
request.AddHeader("accept", "application/json");
request.AddHeader("authorization", "Bearer Your_Token");
var response = await client.GetAsync(request);

Console.WriteLine("{0}", response.Content);
package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	req, _ := http.NewRequest("GET", "https://gate.whapi.cloud/media/{MediaID}", nil)
	req.Header.Set("accept", "application/json")
	req.Header.Set("authorization", "Bearer Your_Token")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	fmt.Println(string(out))
}

Send the door access code

Send the minted door access code as ordinary chat text to the same guest after the document is accepted.

curl --request POST \
     --url https://gate.whapi.cloud/messages/text \
     --header 'accept: application/json' \
     --header 'authorization: Bearer Your_Token' \
     --header 'content-type: application/json' \
     --data '
{
  "to": "447123456789",
  "body": "Your door access code is 482915"
}
'
$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://gate.whapi.cloud/messages/text",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{\"to\":\"447123456789\",\"body\":\"Your door access code is 482915\"}",
  CURLOPT_HTTPHEADER => [
    "accept: application/json",
    "authorization: Bearer Your_Token",
    "content-type: application/json"
  ],
]);

$response = curl_exec($curl);
curl_close($curl);
echo $response;
import requests

url = "https://gate.whapi.cloud/messages/text"
payload = {
    "to": "447123456789",
    "body": "Your door access code is 482915"
}
headers = {
    "accept": "application/json",
    "authorization": "Bearer Your_Token",
    "content-type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)
print(response.text)
const response = await fetch('https://gate.whapi.cloud/messages/text', {
  method: 'POST',
  headers: {
    accept: 'application/json',
    authorization: 'Bearer Your_Token',
    'content-type': 'application/json',
  },
  body: JSON.stringify({
    to: '447123456789',
    body: 'Your door access code is 482915',
  }),
});

console.log(await response.text());
OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\"to\":\"447123456789\",\"body\":\"Your door access code is 482915\"}");
Request request = new Request.Builder()
  .url("https://gate.whapi.cloud/messages/text")
  .post(body)
  .addHeader("accept", "application/json")
  .addHeader("authorization", "Bearer Your_Token")
  .addHeader("content-type", "application/json")
  .build();

Response response = client.newCall(request).execute();
using RestSharp;

var options = new RestClientOptions("https://gate.whapi.cloud/messages/text");
var client = new RestClient(options);
var request = new RestRequest("");
request.AddHeader("accept", "application/json");
request.AddHeader("authorization", "Bearer Your_Token");
request.AddHeader("content-type", "application/json");
request.AddJsonBody(new { to = "447123456789", body = "Your door access code is 482915" });
var response = await client.PostAsync(request);

Console.WriteLine("{0}", response.Content);
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	body := []byte(`{"to":"447123456789","body":"Your door access code is 482915"}`)
	req, _ := http.NewRequest("POST", "https://gate.whapi.cloud/messages/text", bytes.NewReader(body))
	req.Header.Set("accept", "application/json")
	req.Header.Set("authorization", "Bearer Your_Token")
	req.Header.Set("content-type", "application/json")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	fmt.Println(string(out))
}
Delivery status

When the door-code text leaves pending

A successful send response does not mean the guest already has the message. The first status visible before a webhook is pending. Later status changes arrive only on statuses.post and statuses.put. If the status stays pending and does not move to sent, delivered, or a later ack, the message was not delivered—check the payload and the account's permission to send that type.

  • Treat a stuck pending as not delivered, not as a clock or a queue waiting on a webhook.

  • Subscribe to statuses.post and statuses.put when you need sent, delivered, or read confirmation for the door-code text.

  • Do not unlock property access or mark check-in complete while the WhatsApp status stays pending.

What to read on delivery and webhooks

Contact our support if something went wrong
When things break

Handle failures at each step

If the document webhook lacks a usable MediaID, getMedia fails or the file is expired, own_backend rejects the document or cannot mint a code, or sendMessageText fails or stays undelivered, retry or alert reception and do not treat check-in as complete.

Document arrived, but the guest never got a code?

Keep booking acceptance separate from WhatsApp delivery. Fix a missing MediaID, retry getMedia or sendMessageText, or alert reception—do not unlock the door or mark remote check-in done while the guest still has no code. If the send still fails after a retry, contact Whapi support with the channel id and the failed request id.

Contact our support if something went wrong

Troubleshoot by API step

Status What it means What to do
400 Wrong request parameters Fix wrong request parameters on the MediaID path before retrying.
404 Specified media not found Confirm the MediaID from the document webhook still exists in cloud storage, then retry or ask the guest to resend the file.
500 Internal Error
Status What it means What to do
400 Wrong request parameters Fix wrong request parameters in the send body before retrying.
401 Need channel authorization for send message Authorize the channel for send message, then retry with a valid token.
402 Trial version limit exceeded
403 It is forbidden to send to this group/recipient Confirm it is allowed to send to this recipient, then retry with a corrected to value.
413 Request body too large
429 Too many requests Slow down and retry later after too many requests.
500 Internal Error
FAQ

Remote check-in and the door code

No. Matching the passport to the booking, minting the door code, notifying reception, and opening the door stay on your backend. This page covers the WhatsApp document retrieve and the door-code text send.
From the inbound document webhook. In the operator sample, document.id is the MediaID passed to getMedia. When Auto Download is enabled, the same payload may also include a temporary document.link you can fetch directly.
Follow the catalog failure_mode—do not mark check-in complete, retry the failed step or alert reception, and do not unlock access for that guest while media retrieve or delivery is broken.
No. This job is hospitality remote check-in after a guest ID document in a personal chat. It is not an official identity-verification product page and not one-time login code delivery.
The operator story allows a photo or scan of the passport. Wire your webhook filters to the attachment types your property accepts; the retrieve and reply pattern stays the same once you have a MediaID.
Supported WhatsApp Features

Everything you need to build WhatsApp automation

Whapi.Cloud gives you access to a complete set of WhatsApp features — messaging, media, groups, channels, webhooks and more. Build bots, automations and integrations without feature limitations.

Chosen by developers

Trusted by 3,300+ developers and SaaS teams

Developers worldwide rely on Whapi.Cloud to build automations, bots, CRM integrations, bulk messaging tools and advanced WhatsApp workflows. Our infrastructure processes millions of API requests with high stability — and grows every month.

Icon of feature

5,5K+

active API channels

Icon of feature

21M+

API requests processed monthly

“Everything is simple, intuitive and easy to navigate. The docs are clear, and all the info I need is right on the screen. Great job.”

roberto k. / Web Developer

“We connected WhatsApp to our workflows using n8n in just a few minutes. No code, no complications- everything worked on the first try.”

Martin p. / Developer

“Whapi.Cloud became a key part of our customer communication. We automated product updates, order notifications and support messages without needing Meta templates or approvals”

Oscar T. / CTO

Decorative bubble