FAQ and troubleshooting
Numbers and formats
Section titled “Numbers and formats”Which format do phone numbers use?
E.164 — a +, a country code, and the subscriber number: +6281234567890. Spaces, dots, dashes and
parentheses are stripped before validation, so a number as your user typed it usually works. Numbers
without a +, or with a leading 0 instead of a country code, are refused with 400 invalid_input.
Do I see the full number I am renting?
Yes, once the rental is usable. GET /devices returns the full +6281234567890 for an active or past_due
rental — the number is yours to call back — and GET /devices/{id} returns it too, since only a usable rental
reaches that route. A reservation that is not paid yet (pending_payment) and a released rental
(suspended, cancelled, expired) report the storefront mask +62 ••• ••• 7890 instead, with
pushName/hasAvatar/connection blank. The public storefront always masks. Your customers’ numbers —
the ones you send to — are always full E.164.
Can I send to a phone number that is not on WhatsApp?
The send will be accepted and then fail or never deliver. sendState: accepted means WhatsApp took the
message, not that a phone received it. The deliveryState on a later event is the honest answer.
Delivery semantics
Section titled “Delivery semantics”Does 200 mean delivered?
No. It means queued (or, for a notification, accepted for dispatch). Delivery state arrives on your
webhook; the dashboard’s log shows it too.
What does uncertain mean?
MauKirim could not tell whether the message reached WhatsApp — a lease expired, or a transport timed out
mid-attempt. It is neither a failure nor a success, and it is never retried automatically, because a retry
is a possible duplicate and only you can weigh that.
How do I know if a message was delivered?
Configure a webhook for the device and read deliveryState from the events, or read the delivery log at
GET /webhook-deliveries. There is no polling endpoint for a batch.
How long do you keep message content? Seven days after an attempt becomes terminal. Ids, states and timestamps are kept, so your logs and the delivery API still work; the customer’s text is gone.
Idempotency
Section titled “Idempotency”Why is Idempotency-Key required?
Because a send can fail after MauKirim accepted it. Without a key, your only safe options are “never
retry” or “maybe send twice”. With one, a retry returns the original result.
I reused a key and got 409. Why?
The same key with a different request is a conflict by design. Derive keys from the business event (an
order id, a session id), not from the attempt or a counter you might reset.
Does the key expire? No. The record is kept for the life of the account, so a key you used once is still reserved. That is deliberate — it is what makes an old retry detectable rather than a duplicate message.
Where is the code? In the user’s WhatsApp. MauKirim never returns it and stores only a hash. If you need to test without a phone, ask MauKirim for a test number.
The user says the code expired.
Codes live 5 minutes. Issue a new one with a new Idempotency-Key.
I hit 429 rate_limited.
Five OTP issues per hour per (account, phone). It exists to stop an attacker from using you as an SMS
cannon. Let the user press “resend” rather than resending on a timer.
verified: false for a code I am sure is right.
Check, in order: the challenge is more than 5 minutes old; 5 attempts were already used (a wrong guess burns
one, and after five even the right code fails); the challenge was already verified once; or the OTP message
was never accepted by the gateway.
Notifications
Section titled “Notifications”400 invalid_input mentioning variables.
Your variables keys must match the template’s top-level placeholders exactly — same names, same count.
For {{#items}}...{{/items}}, send items as an array of objects; every object must match the fields
inside that section, with no missing or extra keys.
Can I send arbitrary text as a notification?
No, and that is on purpose: a notification goes out from MauKirim’s own number, so its content is bound to a
template an operator approved. For free-form text, rent a number and use
POST /devices/{id}/messages.
Webhooks
Section titled “Webhooks”Nothing arrives at my endpoint.
Check, in this order: is the destination active; does GET /devices/{id}/webhook report
gatewayWired: true; and what does GET /webhook-deliveries say? If the deliveries are there with
endpoint_unreachable, your endpoint is not answering; endpoint_rejected means it answered non-2xx.
The same event arrived twice.
Retries reuse the same x-maukirim-delivery id — deduplicate on it. Every delivery is at-least-once.
My signature check fails. You are almost certainly hashing something other than the exact bytes received — parsing and re-encoding JSON changes them. Hash the raw body, and compare with a timing-safe function.
How long do you retry?
Up to 5 attempts over about 45 minutes (0s, 30s, 2m, 10m, 30m), then the delivery is exhausted.
Google Business
Section titled “Google Business”Which packages include Google Business?
Growth and every package above it. Without it, every /gmb/... call answers 402 gmb_plan_required. It is
never billed from credits; the package decides how many businesses you can connect (10, 50, 200 or 1,000).
Can an API key or an assistant connect a Google account for me?
No. The owner of the Google account must approve Google’s consent screen in a browser. You connect your own in
the dashboard (the MCP tool get_gmb_connect_link only returns that link). For your own clients there is the
hosted flow: your server creates a connect session and sends the client the link; the client approves on a page
MauKirim hosts, with no MauKirim account. See Connect your clients. An API key
can disconnect a connection (DELETE /gmb/connections/{id}), which is how you offboard a client.
Does my client need a MauKirim account to connect their Business Profile?
No. The link from a connect session is the only thing they need; they sign in to Google, not to MauKirim. The
businesses they connect belong to your account. They arrive switched off and cost no allowance; you turn on the ones you want with POST /gmb/locations/activation, and only active businesses count against your allowance.
What comes back when my client finishes?
Their browser is sent to your registered return address with maukirim_session, status (success,
cancelled or error), external_id, connection_id (on success) and error (access_denied when they
declined, or a gmb_* code). It carries no secret; confirm it by reading the session with your API key.
Why was my connect session refused with gmb_redirect_not_allowed?
The redirectUrl is not inside an address you registered (POST /gmb/redirect-uris), or it is not https
(http is allowed only for localhost), or it has credentials or a fragment. Nothing was created.
How long does a connect link last? 30 minutes, and one trip. After that, or once the trip ended, create a new session.
Can MauKirim publish Google posts and photos, or read insights?
Yes: posts, photos (uploaded as a JPEG or PNG file, or added by URL) and
insights, plus attributes, categories, verification and an allow-listed
door to the other Business Profile APIs. Some of those Google APIs have
to be enabled and approved for the deployment’s Google project; an unavailable one answers 503 gmb_api_unavailable.
Questions and answers are not offered.
Can I upload a photo file, or must it be a URL?
Both work. POST /gmb/locations/{id}/media/upload
takes a multipart file: JPEG or PNG, 10 KB to 5 MB, judged by its bytes rather than its name. It costs three
Google calls. Videos can only be added by public URL. Over MCP the tool is upload_gmb_media (base64 file).
Can I create a new business on Google, or delete one?
Yes. POST /gmb/connections/{id}/locations
creates one under a connected Google account (try validateOnly first); it counts against your business
allowance and starts unverified, so verify it.
DELETE /gmb/locations/{id} removes a business from Google
and needs its exact title typed back. Over MCP: create_gmb_location and delete_gmb_location.
Can I add someone as a manager of a business?
Yes, as MANAGER or SITE_MANAGER: POST /gmb/locations/{id}/admins. Google
emails them the invitation. Ownership cannot be handed over through MauKirim; the current owner does that in Google.
Which Google Business calls are risky for an assistant?
Anything that changes a public listing: over MCP those tools need confirm: true (and an idempotency_key where
a retry would repeat the change), and are refused without them before Google is called. See MCP.
429 gmb_rate_limited — is something broken?
No. Google gives MauKirim 300 queries a minute for all customers together, and each account has its own share
(60 by default). The response says how long to wait in Retry-After and retryAfterSeconds; wait that long and
retry with the same Idempotency-Key. See Google Business rate limits.
Which calls cost budget?
Listing businesses and reading the stored copy are free (they come from MauKirim’s own table), and so are
connect sessions and return addresses; a review page costs one call once a minute (it is cached for 60 seconds);
an edit, a reply, ?live=1, a post, a photo added by URL, insights, attributes, verification, creating or deleting a
business, inviting a manager and a call through the Google door cost one call each; a photo upload costs three. See Google Business rate limits.
I got a new business in Google but it is not in the list.
Sync the connection from the dashboard, or queue POST /gmb/locations/{id}/refresh for a business you already
have. A business found by a sync arrives switched off (status: disabled, disabledBy: user) and costs no allowance: list GET /gmb/locations?status=disabled and turn it on with POST /gmb/locations/activation.
A business answers 404 gmb_location_not_found but I own it.
Either its id is wrong (the answer is identical for an id that is not yours), or it has left the Google account
— removed_upstream — because the manager access was removed. Check GET /gmb/locations?status=removed_upstream.
A connection says needs_reauth.
Google no longer accepts the permission. Reconnect the same Google account in Services → Google Business.
How do I remove MauKirim’s access to Google?
Disconnect in the dashboard (or with DELETE /gmb/connections/{id}), or remove MauKirim at myaccount.google.com/permissions.
Details on Google Business Profile.
Keys and access
Section titled “Keys and access”How do I rotate a key? Create the new one, deploy it, then revoke the old one from the dashboard. Both are valid in between, so plan for that window.
I lost a key. There is no way to read it back — MauKirim stores only a hash. Revoke it and create another.
A device id I know exists answers 404 rental_not_found.
That is the intended answer for a device that is not currently rented by your account, and it is identical
to the answer for a device that does not exist, so the API never confirms which ids are real. Check the
rental’s status in GET /devices.
Support
Section titled “Support”When you contact support, include the batchId (sends), the challengeId (OTP), the delivery id
(whd_…, webhooks), the time with a timezone, and the exact error code. Those five facts turn “it did not
work” into something answerable in one pass. Never include an API key.