💬 Shared WhatsApp Inbox on the new PlatformMore
1msg official logo

Document resubmission request via WhatsApp API

The scenario sends the client a personalized WhatsApp template when a submitted document cannot be accepted and they must upload it again.

Use case overview

The scenario sends the client a personalized WhatsApp template when a submitted document cannot be accepted and they must upload it again. The message includes the client name, document type, and resubmit instructions (e.g. blurry image, expired date). A static URL button opens the upload portal or form.

Template example

Hello, {{1}}! We could not accept your {{2}}. {{3}} Please upload the document again using the button below. If you have questions — we are here to help.

Resubmit document
  • {{1}}
    customer name
  • {{2}}
    document type to resubmit (e.g. passport scan, proof of address, income statement)
  • {{3}}
    resubmit reason or instruction (e.g. image was blurry, upload a color photo by Friday)
  • “Resubmit document”
    button — fixed in the Meta template
WhatsApp Business API for document resubmit request

When to use it

Reach for this scenario when a client uploaded a document during onboarding, KYC, or checkout but review rejected it — and they stalled or abandoned before resubmitting, with no open WhatsApp conversation to chase them in session. It fits product teams unblocking identity verification, lending and finance flows waiting on clearer scans or signed forms, and agencies wiring document-review webhooks from CRM or BPM into WhatsApp resubmit nudges.

Stalled flows unblocked without email ping-pong
Three body variables carry the client name, document type, and the specific resubmit instruction, so the client knows what to fix instead of guessing from a generic rejection email.
Reach clients outside the 24-hour window
Because the client has no open chat, an approved WhatsApp template is the only allowed first message — this scenario sends that template with document context instead of waiting for them to write first.
Upload again in one tap
The static URL button fixed in the Meta template opens the upload portal or form, so the client can resubmit from WhatsApp without hunting for a link in email.
No agent retyping on every rejection
When document review flags resubmit, the system resolves the phone and builds the template from review fields — no rep copies document types or rewrites the ask by hand.
Delivery logged for workflow follow-up
Delivery result is logged after send for CRM or workflow follow-up, and the client can continue in session once they reply or upload.

Workflow

  1. Trigger

    Document review or workflow flags that the client must resubmit a document.

    event · triggered

  2. Capture event

    The system resolves the recipient phone number and resubmit fields.

    phone: "+…"

  3. Build & send

    A personalized template message is built with three body variables and a static URL button.

    POST /sendTemplate

  4. Delivered

    The client receives the WhatsApp resubmit request with document context and instructions.

    delivered

  5. Status tracked

    Delivery result is logged; client may upload via portal and continue in session after reply.

    status: "read"

WhatsApp Business API for document resubmit request

Technical implementation

Prerequisites

  1. 1MSG API Key · How to get API Key
  2. WhatsApp Business account · How to Connect WABA
  3. WhatsApp Template · How to Approve WABA Template
  4. Customer opt-in · How to Manage Customers Consent

Code examples

#!/usr/bin/env bash
set -euo pipefail

# === Configuration (replace "___" placeholders) ===

API_BASE_URL="https://api.1msg.io"        # production 1MSG API base URL
CHANNEL_ID="___"                           # channel ID from 1MSG dashboard
API_TOKEN="___"                            # channel JWT token (Bearer)

TEMPLATE_NAME="___"                        # approved template name
TEMPLATE_NAMESPACE="___"                   # template namespace (required — send fails without it)
TEMPLATE_LANGUAGE="___"                    # template language code, e.g. "en"



# === Test data ===
TEST_PHONE="___"                 # client phone in international format
TEST_CUSTOMERNAME="___"         # {{1}} customer name
TEST_AWAITEDITEM="___"         # {{2}} awaited item
TEST_ADDITIONALINFO="___"         # {{3}} additional info

PHONE_NORM="$(printf '%s' "$TEST_PHONE" | tr -cd '0-9')"

for pair in "CHANNEL_ID=$CHANNEL_ID" "API_TOKEN=$API_TOKEN" \
            "TEMPLATE_NAME=$TEMPLATE_NAME" "TEMPLATE_NAMESPACE=$TEMPLATE_NAMESPACE" \
            "TEMPLATE_LANGUAGE=$TEMPLATE_LANGUAGE" "TEST_PHONE=$TEST_PHONE" \
            "TEST_CUSTOMERNAME=$TEST_CUSTOMERNAME" \
            "TEST_AWAITEDITEM=$TEST_AWAITEDITEM" \
            "TEST_ADDITIONALINFO=$TEST_ADDITIONALINFO"; do
    val="${pair#*=}"
    if [ -z "$val" ] || [ "$val" = "___" ]; then
        echo "Missing configuration value: ${pair%%=*}" >&2
        exit 1
    fi
done

if [ -z "$PHONE_NORM" ]; then
    echo "Error: phone number has no digits after normalization" >&2
    exit 1
fi

URL="${API_BASE_URL%/}/${CHANNEL_ID}/sendTemplate"

# params carries body ONLY. Button text is fixed in the Meta template — no button param.

# {{1}} customer name → ${TEST_CUSTOMERNAME}
# {{2}} awaited item → ${TEST_AWAITEDITEM}
# {{3}} additional info → ${TEST_ADDITIONALINFO}
read -r -d '' PAYLOAD <<JSON || true
{
  "phone": "${PHONE_NORM}",
  "template": "${TEMPLATE_NAME}",
  "namespace": "${TEMPLATE_NAMESPACE}",
  "language": { "policy": "deterministic", "code": "${TEMPLATE_LANGUAGE}" },
  "params": [
    {
      "type": "body",
      "parameters": [
        { "type": "text", "text": "${TEST_CUSTOMERNAME}" },
        { "type": "text", "text": "${TEST_AWAITEDITEM}" },
        { "type": "text", "text": "${TEST_ADDITIONALINFO}" }
      ]
    }

  ]
}
JSON

RESPONSE="$(curl -s -w '\n%{http_code}' -X POST "$URL" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer ${API_TOKEN}" \
    -d "$PAYLOAD")"

HTTP_CODE="$(printf '%s' "$RESPONSE" | tail -n1)"
BODY="$(printf '%s' "$RESPONSE" | sed '$d')"

case "$BODY" in
    *'"sent":true'*) ok=1 ;;
    *) ok=0 ;;
esac

if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ] && [ "$ok" -eq 1 ]; then
    echo "Message sent to client."
    echo "API response: $BODY"
else
    echo "Send failed. HTTP status: $HTTP_CODE" >&2
    echo "$BODY" >&2
    exit 1
fi

Response and delivery status

HTTP 2xx and JSON "sent": true mean 1MSG accepted the message for sending — not that it already reached the customer's phone. Save the id field (looks like wamid.…) to correlate delivery callbacks.

200 OKResponse
{
  "sent": true,
  "message": "Sent to [email protected]",
  "description": "Message has been sent to the provider",
  "id": "wamid.HBgLMzgwNjM5..."
}
  • sent

    Accepted for sending — not yet on the customer's phone

  • id

    Store it; delivery callbacks and hookInfo are keyed on this

Delivery statuses and webhooks →

Common errors

StatusAPI responseCauseFix
200Message was not sent: template is not definednamespace, template or language is missing from the request body.Send all three. Take namespace and the exact template name from GET /templates; language is an object: {"policy": "deterministic", "code": "en"}.
200template name (…) does not exist in <language>The template is approved in a different language than the one requested.Use the exact language code the template was approved in (for example es_MX is not the same as es). Check it in GET /templates.
200Message was not sent: provide chatId, phone, bsuid, or usernameNo recipient the channel could resolve.Pass exactly one recipient: phone (country code plus number, digits only), chatId (for example [email protected]) or bsuid.

All error codes →

Common questions

Related

Build for WhatsApp in hours
without infrastructure hassle