Skip to content

FAQ and troubleshooting

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.

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.

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.

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.

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.

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.

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.

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.