APIs & Integrações2 de mar. de 2026· 15 min leitura

How to Send Images, Videos, and Documents via WhatsApp Business API

Complete technical guide to sending media via WhatsApp Cloud API: sending by public URL, pre-upload with media_id, supported formats, size limits, Node.js and Python examples, and error handling.

Sending text via WhatsApp is straightforward. Sending media — images, videos, audio, documents — requires understanding two distinct flows that the WhatsApp Cloud API provides, each with its own advantages and limitations.

This guide covers everything: formats and limits per media type, when to use a direct URL versus pre-upload, required headers, production-ready code examples in Node.js and Python, and how to handle the most common errors. At the end, you'll have a reusable helper function that detects the media type and routes to the correct endpoint.

The Two Media Sending Flows

The Cloud API supports two ways to reference media in a message:

1. By public URL — You pass a publicly accessible URL in the message payload. Meta fetches the file from that URL at the time of sending.

2. By media_id (pre-upload) — You first upload the file to Meta's servers via POST /media, receive a media_id, and use that ID when sending the message.

When to use each flow

| Situation | Recommended flow | |---|---| | File already hosted on CDN/S3 | Public URL | | Dynamically generated file (invoice PDF, etc.) | Pre-upload | | Same file sent to many users | Pre-upload (reuse media_id) | | Sensitive file that can't be public | Pre-upload | | Prototyping and quick tests | Public URL |

The media_id is valid for 30 days from the time of upload. After that, it needs to be re-uploaded.

Supported Formats and Size Limits

Before writing any code, it's essential to know the API limits. Sending an unsupported format or a file that exceeds the limit results in an immediate error.

Images

| Format | Size limit | |---|---| | JPEG | 5 MB | | PNG | 5 MB | | WebP | 100 KB (animated stickers only) |

Note: The image limit applies to both URL-based sending and pre-upload. Resize or compress images before sending to avoid rejections.

Videos

| Format | Video codec | Audio codec | Limit | |---|---|---|---| | MP4 | H.264 | AAC | 16 MB | | 3GP | H.264 | AAC | 16 MB |

Videos with codecs other than H.264 (such as VP9 or AV1) are rejected even if the container is .mp4. Verify the codec before sending.

Documents

| Format | Limit | |---|---| | PDF | 100 MB | | DOC / DOCX | 100 MB | | XLS / XLSX | 100 MB | | PPT / PPTX | 100 MB | | TXT | 100 MB |

Audio

| Format | Limit | |---|---| | AAC | 16 MB | | MP4 (audio only) | 16 MB | | MPEG | 16 MB | | AMR | 16 MB | | OGG (Opus only) | 16 MB |

Note: OGG audio with Opus codec is played as a voice message inside WhatsApp. Other audio formats appear as audio file attachments.

Message Payload Structure for Media

Regardless of the media type or flow used, the base payload structure is always the same:

{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "15551234567",
  "type": "image",
  "image": {
    "link": "https://yoursite.com/image.jpg",
    "caption": "Optional image caption"
  }
}

To use media_id instead of a URL:

{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "15551234567",
  "type": "image",
  "image": {
    "id": "1234567890123456",
    "caption": "Optional image caption"
  }
}

The field that changes is the type (image, video, document, audio) and the corresponding object with either link or id.

Sending endpoint

POST https://graph.facebook.com/v21.0/{PHONE_NUMBER_ID}/messages

Authentication via Authorization: Bearer {TOKEN} header.

Sending Media by Public URL

Node.js

const axios = require('axios')

const PHONE_NUMBER_ID = process.env.WHATSAPP_PHONE_NUMBER_ID
const TOKEN = process.env.WHATSAPP_TOKEN
const BASE_URL = `https://graph.facebook.com/v21.0/${PHONE_NUMBER_ID}/messages`

async function sendImage(to, imageUrl, caption = '') {
  const response = await axios.post(
    BASE_URL,
    {
      messaging_product: 'whatsapp',
      recipient_type: 'individual',
      to,
      type: 'image',
      image: {
        link: imageUrl,
        ...(caption && { caption }),
      },
    },
    {
      headers: {
        Authorization: `Bearer ${TOKEN}`,
        'Content-Type': 'application/json',
      },
    }
  )
  return response.data
}

async function sendVideo(to, videoUrl, caption = '') {
  const response = await axios.post(
    BASE_URL,
    {
      messaging_product: 'whatsapp',
      recipient_type: 'individual',
      to,
      type: 'video',
      video: {
        link: videoUrl,
        ...(caption && { caption }),
      },
    },
    {
      headers: {
        Authorization: `Bearer ${TOKEN}`,
        'Content-Type': 'application/json',
      },
    }
  )
  return response.data
}

async function sendDocument(to, documentUrl, filename, caption = '') {
  const response = await axios.post(
    BASE_URL,
    {
      messaging_product: 'whatsapp',
      recipient_type: 'individual',
      to,
      type: 'document',
      document: {
        link: documentUrl,
        filename, // Name shown in the recipient's WhatsApp
        ...(caption && { caption }),
      },
    },
    {
      headers: {
        Authorization: `Bearer ${TOKEN}`,
        'Content-Type': 'application/json',
      },
    }
  )
  return response.data
}

// Usage examples
sendImage('15551234567', 'https://yoursite.com/product.jpg', 'New product available!')
sendVideo('15551234567', 'https://yoursite.com/demo.mp4', 'See how it works')
sendDocument('15551234567', 'https://yoursite.com/invoice.pdf', 'invoice-january-2026.pdf', 'Your January invoice')

Python

import os
import requests

PHONE_NUMBER_ID = os.environ['WHATSAPP_PHONE_NUMBER_ID']
TOKEN = os.environ['WHATSAPP_TOKEN']
BASE_URL = f'https://graph.facebook.com/v21.0/{PHONE_NUMBER_ID}/messages'

HEADERS = {
    'Authorization': f'Bearer {TOKEN}',
    'Content-Type': 'application/json',
}

def send_image(to: str, image_url: str, caption: str = '') -> dict:
    payload = {
        'messaging_product': 'whatsapp',
        'recipient_type': 'individual',
        'to': to,
        'type': 'image',
        'image': {'link': image_url},
    }
    if caption:
        payload['image']['caption'] = caption

    response = requests.post(BASE_URL, json=payload, headers=HEADERS)
    response.raise_for_status()
    return response.json()

def send_video(to: str, video_url: str, caption: str = '') -> dict:
    payload = {
        'messaging_product': 'whatsapp',
        'recipient_type': 'individual',
        'to': to,
        'type': 'video',
        'video': {'link': video_url},
    }
    if caption:
        payload['video']['caption'] = caption

    response = requests.post(BASE_URL, json=payload, headers=HEADERS)
    response.raise_for_status()
    return response.json()

def send_document(to: str, doc_url: str, filename: str, caption: str = '') -> dict:
    payload = {
        'messaging_product': 'whatsapp',
        'recipient_type': 'individual',
        'to': to,
        'type': 'document',
        'document': {
            'link': doc_url,
            'filename': filename,
        },
    }
    if caption:
        payload['document']['caption'] = caption

    response = requests.post(BASE_URL, json=payload, headers=HEADERS)
    response.raise_for_status()
    return response.json()

# Usage examples
send_image('15551234567', 'https://yoursite.com/product.jpg', 'New product available!')
send_video('15551234567', 'https://yoursite.com/demo.mp4', 'See how it works')
send_document('15551234567', 'https://yoursite.com/invoice.pdf', 'invoice-january-2026.pdf', 'Your January invoice')

Pre-Upload via POST /media

When you don't have a public URL or want to reuse a file across multiple sends, the correct flow is to upload the file first and get a media_id.

Upload endpoint

POST https://graph.facebook.com/v21.0/{PHONE_NUMBER_ID}/media

Required headers

The upload uses multipart/form-data, not JSON. Required fields:

  • messaging_product: always "whatsapp"
  • type: MIME type of the file (e.g., image/jpeg, video/mp4, application/pdf)
  • file: the file itself

Important: The HTTP Content-Type header must be multipart/form-data with the correct boundary. Libraries like axios and requests handle this automatically when you use FormData.

Node.js — File upload

const axios = require('axios')
const FormData = require('form-data')
const fs = require('fs')
const path = require('path')

const PHONE_NUMBER_ID = process.env.WHATSAPP_PHONE_NUMBER_ID
const TOKEN = process.env.WHATSAPP_TOKEN

const MIME_TYPES = {
  '.jpg': 'image/jpeg',
  '.jpeg': 'image/jpeg',
  '.png': 'image/png',
  '.webp': 'image/webp',
  '.mp4': 'video/mp4',
  '.3gp': 'video/3gpp',
  '.pdf': 'application/pdf',
  '.doc': 'application/msword',
  '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  '.xls': 'application/vnd.ms-excel',
  '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  '.aac': 'audio/aac',
  '.mp3': 'audio/mpeg',
  '.ogg': 'audio/ogg',
}

async function uploadMedia(filePath) {
  const ext = path.extname(filePath).toLowerCase()
  const mimeType = MIME_TYPES[ext]

  if (!mimeType) {
    throw new Error(`Unsupported format: ${ext}`)
  }

  const form = new FormData()
  form.append('messaging_product', 'whatsapp')
  form.append('type', mimeType)
  form.append('file', fs.createReadStream(filePath), {
    filename: path.basename(filePath),
    contentType: mimeType,
  })

  const response = await axios.post(
    `https://graph.facebook.com/v21.0/${PHONE_NUMBER_ID}/media`,
    form,
    {
      headers: {
        Authorization: `Bearer ${TOKEN}`,
        ...form.getHeaders(),
      },
    }
  )

  return response.data.id // Returns the media_id
}

async function sendMediaById(to, mediaId, mediaType, options = {}) {
  const typeMap = {
    'image/jpeg': 'image',
    'image/png': 'image',
    'video/mp4': 'video',
    'application/pdf': 'document',
    'audio/ogg': 'audio',
  }

  const whatsappType = typeMap[mediaType] || 'document'

  const payload = {
    messaging_product: 'whatsapp',
    recipient_type: 'individual',
    to,
    type: whatsappType,
    [whatsappType]: {
      id: mediaId,
      ...options,
    },
  }

  const response = await axios.post(
    `https://graph.facebook.com/v21.0/${PHONE_NUMBER_ID}/messages`,
    payload,
    {
      headers: {
        Authorization: `Bearer ${TOKEN}`,
        'Content-Type': 'application/json',
      },
    }
  )

  return response.data
}

// Example: upload then send
async function uploadAndSend(to, filePath, caption = '') {
  const mediaId = await uploadMedia(filePath)
  console.log(`Media uploaded: ${mediaId}`)

  const ext = path.extname(filePath).toLowerCase()
  const mimeType = MIME_TYPES[ext]

  return sendMediaById(to, mediaId, mimeType, {
    ...(caption && { caption }),
    ...(mimeType === 'application/pdf' && { filename: path.basename(filePath) }),
  })
}

// Usage
uploadAndSend('15551234567', './invoice-jan-2026.pdf', 'Your January invoice')

Python — File upload

import os
import requests
from pathlib import Path

PHONE_NUMBER_ID = os.environ['WHATSAPP_PHONE_NUMBER_ID']
TOKEN = os.environ['WHATSAPP_TOKEN']

MIME_MAP = {
    '.jpg': 'image/jpeg',
    '.jpeg': 'image/jpeg',
    '.png': 'image/png',
    '.webp': 'image/webp',
    '.mp4': 'video/mp4',
    '.3gp': 'video/3gpp',
    '.pdf': 'application/pdf',
    '.doc': 'application/msword',
    '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    '.xls': 'application/vnd.ms-excel',
    '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    '.aac': 'audio/aac',
    '.mp3': 'audio/mpeg',
    '.ogg': 'audio/ogg',
}

WHATSAPP_TYPE_MAP = {
    'image/jpeg': 'image',
    'image/png': 'image',
    'image/webp': 'image',
    'video/mp4': 'video',
    'video/3gpp': 'video',
    'application/pdf': 'document',
    'audio/aac': 'audio',
    'audio/mpeg': 'audio',
    'audio/ogg': 'audio',
}

def upload_media(file_path: str) -> str:
    """Uploads a file to the API and returns the media_id."""
    file_path = Path(file_path)
    ext = file_path.suffix.lower()
    mime_type = MIME_MAP.get(ext)

    if not mime_type:
        raise ValueError(f'Unsupported format: {ext}')

    upload_url = f'https://graph.facebook.com/v21.0/{PHONE_NUMBER_ID}/media'

    with open(file_path, 'rb') as f:
        files = {
            'file': (file_path.name, f, mime_type),
        }
        data = {
            'messaging_product': 'whatsapp',
            'type': mime_type,
        }
        response = requests.post(
            upload_url,
            headers={'Authorization': f'Bearer {TOKEN}'},
            files=files,
            data=data,
        )

    response.raise_for_status()
    return response.json()['id']


def send_media_by_id(
    to: str,
    media_id: str,
    mime_type: str,
    caption: str = '',
    filename: str = '',
) -> dict:
    """Sends a message using an already obtained media_id."""
    whatsapp_type = WHATSAPP_TYPE_MAP.get(mime_type, 'document')

    media_object = {'id': media_id}
    if caption:
        media_object['caption'] = caption
    if filename and whatsapp_type == 'document':
        media_object['filename'] = filename

    payload = {
        'messaging_product': 'whatsapp',
        'recipient_type': 'individual',
        'to': to,
        'type': whatsapp_type,
        whatsapp_type: media_object,
    }

    messages_url = f'https://graph.facebook.com/v21.0/{PHONE_NUMBER_ID}/messages'
    response = requests.post(
        messages_url,
        json=payload,
        headers={
            'Authorization': f'Bearer {TOKEN}',
            'Content-Type': 'application/json',
        },
    )
    response.raise_for_status()
    return response.json()


def upload_and_send(to: str, file_path: str, caption: str = '') -> dict:
    """Uploads and sends in a single call."""
    file_path = Path(file_path)
    ext = file_path.suffix.lower()
    mime_type = MIME_MAP.get(ext, 'application/octet-stream')

    media_id = upload_media(str(file_path))
    print(f'Upload complete. media_id: {media_id}')

    return send_media_by_id(
        to=to,
        media_id=media_id,
        mime_type=mime_type,
        caption=caption,
        filename=file_path.name,
    )

# Usage
upload_and_send('15551234567', './invoice-jan-2026.pdf', 'Your January invoice')

Reusable Helper Function

For a unified interface that automatically detects the media type and chooses the correct flow, here's a complete helper in Node.js:

const axios = require('axios')
const FormData = require('form-data')
const fs = require('fs')
const path = require('path')

const PHONE_NUMBER_ID = process.env.WHATSAPP_PHONE_NUMBER_ID
const TOKEN = process.env.WHATSAPP_TOKEN

const MEDIA_CONFIG = {
  'image/jpeg':   { type: 'image',    maxMB: 5,   ext: ['.jpg', '.jpeg'] },
  'image/png':    { type: 'image',    maxMB: 5,   ext: ['.png'] },
  'image/webp':   { type: 'image',    maxMB: 0.1, ext: ['.webp'] },
  'video/mp4':    { type: 'video',    maxMB: 16,  ext: ['.mp4'] },
  'video/3gpp':   { type: 'video',    maxMB: 16,  ext: ['.3gp'] },
  'application/pdf': { type: 'document', maxMB: 100, ext: ['.pdf'] },
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
                  { type: 'document', maxMB: 100, ext: ['.docx'] },
  'audio/aac':    { type: 'audio',    maxMB: 16,  ext: ['.aac'] },
  'audio/mpeg':   { type: 'audio',    maxMB: 16,  ext: ['.mp3'] },
  'audio/ogg':    { type: 'audio',    maxMB: 16,  ext: ['.ogg'] },
}

const EXT_TO_MIME = Object.entries(MEDIA_CONFIG).reduce((acc, [mime, cfg]) => {
  cfg.ext.forEach((e) => (acc[e] = mime))
  return acc
}, {})

/**
 * Sends media via WhatsApp Cloud API.
 *
 * @param {Object} options
 * @param {string} options.to          - Recipient number (with country code, without +)
 * @param {string} [options.url]       - Public URL of the file
 * @param {string} [options.filePath]  - Local file path (for pre-upload)
 * @param {string} [options.caption]   - Media caption (optional)
 * @param {string} [options.filename]  - File name for documents (optional)
 */
async function sendMedia({ to, url, filePath, caption, filename }) {
  if (!url && !filePath) {
    throw new Error('Provide either "url" or "filePath".')
  }

  // --- URL flow ---
  if (url) {
    const ext = path.extname(new URL(url).pathname).toLowerCase()
    const mime = EXT_TO_MIME[ext]
    if (!mime) throw new Error(`Unsupported extension: ${ext}`)

    const { type } = MEDIA_CONFIG[mime]
    const mediaObject = { link: url }
    if (caption) mediaObject.caption = caption
    if (filename && type === 'document') mediaObject.filename = filename

    const res = await axios.post(
      `https://graph.facebook.com/v21.0/${PHONE_NUMBER_ID}/messages`,
      {
        messaging_product: 'whatsapp',
        recipient_type: 'individual',
        to,
        type,
        [type]: mediaObject,
      },
      { headers: { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json' } }
    )
    return res.data
  }

  // --- Pre-upload flow ---
  const ext = path.extname(filePath).toLowerCase()
  const mime = EXT_TO_MIME[ext]
  if (!mime) throw new Error(`Unsupported extension: ${ext}`)

  const { type, maxMB } = MEDIA_CONFIG[mime]
  const stats = fs.statSync(filePath)
  const fileMB = stats.size / (1024 * 1024)

  if (fileMB > maxMB) {
    throw new Error(`File exceeds the ${maxMB}MB limit for ${type} (${fileMB.toFixed(2)}MB)`)
  }

  const form = new FormData()
  form.append('messaging_product', 'whatsapp')
  form.append('type', mime)
  form.append('file', fs.createReadStream(filePath), {
    filename: path.basename(filePath),
    contentType: mime,
  })

  const uploadRes = await axios.post(
    `https://graph.facebook.com/v21.0/${PHONE_NUMBER_ID}/media`,
    form,
    { headers: { Authorization: `Bearer ${TOKEN}`, ...form.getHeaders() } }
  )

  const mediaId = uploadRes.data.id
  const mediaObject = { id: mediaId }
  if (caption) mediaObject.caption = caption
  mediaObject.filename = filename || path.basename(filePath)

  const sendRes = await axios.post(
    `https://graph.facebook.com/v21.0/${PHONE_NUMBER_ID}/messages`,
    {
      messaging_product: 'whatsapp',
      recipient_type: 'individual',
      to,
      type,
      [type]: mediaObject,
    },
    { headers: { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json' } }
  )

  return { mediaId, message: sendRes.data }
}

module.exports = { sendMedia }

// --- Examples ---
// Send by URL:
// sendMedia({ to: '15551234567', url: 'https://cdn.yoursite.com/photo.jpg', caption: 'Check this out!' })

// Send by upload:
// sendMedia({ to: '15551234567', filePath: './report.pdf', filename: 'report-march-2026.pdf' })

Handling Common Errors

The API returns errors with 4xx or 5xx HTTP codes and an error object in the body. The most frequent media errors:

Error 131053 — Invalid media format

{
  "error": {
    "code": 131053,
    "message": "Media type not supported.",
    "error_data": { "details": "The media format is not supported." }
  }
}

Cause: File with correct extension but incompatible codec (e.g., video with VP9 codec), or corrupted file.

Solution: Convert the file before sending. For video:

ffmpeg -i input.mov -vcodec h264 -acodec aac output.mp4

Error 131052 — Inaccessible URL

{
  "error": {
    "code": 131052,
    "message": "Media URL is not accessible.",
    "error_data": { "details": "Failed to download the media." }
  }
}

Cause: The URL returned 401, 403, 404, or timed out. Meta attempts to fetch the file at the time of sending.

Solution: Make sure the URL is public, requires no authentication, and is externally accessible. Test with curl -I <URL> before sending.

Error 131051 — File size too large

{
  "error": {
    "code": 131051,
    "message": "Media file size too large.",
    "error_data": { "details": "Media file size exceeds the limit." }
  }
}

Cause: The file exceeds the limits described earlier.

Solution: Compress or resize before sending. For images, use sharp (Node.js) or Pillow (Python). For PDFs, use ghostscript.

Centralized error handling

async function sendMediaSafe(options) {
  try {
    return await sendMedia(options)
  } catch (error) {
    if (error.response) {
      const { code, message } = error.response.data?.error || {}
      switch (code) {
        case 131051:
          throw new Error(`File too large. Compress before sending. (${message})`)
        case 131052:
          throw new Error(`URL inaccessible by Meta. Ensure it is public. (${message})`)
        case 131053:
          throw new Error(`Unsupported format. Convert the file. (${message})`)
        default:
          throw new Error(`API error (${code}): ${message}`)
      }
    }
    throw error
  }
}
def send_media_safe(**kwargs):
    """Wrapper with structured error handling."""
    error_messages = {
        131051: 'File too large. Compress before sending.',
        131052: 'URL inaccessible by Meta. Ensure it is public.',
        131053: 'Unsupported format. Convert the file.',
    }
    try:
        return upload_and_send(**kwargs)
    except requests.exceptions.HTTPError as e:
        error_data = e.response.json().get('error', {})
        code = error_data.get('code')
        api_msg = error_data.get('message', '')
        friendly = error_messages.get(code, f'API error ({code})')
        raise RuntimeError(f'{friendly} — {api_msg}') from e

Managing Media IDs

If you reuse the same file for multiple users (e.g., a catalog PDF sent to your entire contact list), it makes sense to upload once and cache the media_id.

// Simple in-memory media_id cache
// In production, use Redis or a database
const mediaCache = new Map()

async function getOrUploadMedia(filePath) {
  if (mediaCache.has(filePath)) {
    return mediaCache.get(filePath)
  }

  const mediaId = await uploadMedia(filePath)
  // media_id is valid for 30 days — in production, store with expiration timestamp
  mediaCache.set(filePath, mediaId)
  return mediaId
}

// Batch send to multiple recipients
async function broadcastDocument(recipients, filePath, caption) {
  const mediaId = await getOrUploadMedia(filePath)
  const filename = path.basename(filePath)

  const results = await Promise.allSettled(
    recipients.map((to) =>
      sendMediaById(to, mediaId, 'application/pdf', caption, filename)
    )
  )

  const successes = results.filter((r) => r.status === 'fulfilled').length
  const failures = results.filter((r) => r.status === 'rejected').length
  console.log(`Sent: ${successes} ✅ | Failed: ${failures} ❌`)
  return results
}

Best Practices

Validate before sending. Check file size and format on your server before calling the API. This avoids unnecessary round-trips and improves the error experience for the end user.

For URLs, use CDN with HTTPS. Meta rejects HTTP URLs (no SSL). Use a CDN (Cloudflare, AWS CloudFront, etc.) to ensure availability and download speed.

Prefer pre-upload for large-scale sends. If you're sending the same file to hundreds or thousands of users, a single upload and media_id reuse is far more efficient than having Meta fetch the file on each send.

Captions are optional but useful. For images and videos, the caption appears as text below the media. For documents, use the filename field to give a friendly name — the user will see that name before downloading.

Monitor 131052 errors actively. URLs that work today may stop working tomorrow (deleted file, CDN outage, signed URL expiration). Implement logs and alerts for this error.

Summary

Sending media via the WhatsApp Cloud API is straightforward once you understand the two flows and the limits per file type.

The key points:

  • Public URL for already-hosted files; pre-upload for local, sensitive, or reused files
  • Images: JPEG/PNG up to 5 MB; Videos: MP4 with H.264 up to 16 MB; Documents: PDF and Office up to 100 MB
  • The upload uses multipart/form-data with the messaging_product, type, and file fields
  • The media_id is valid for 30 days — worth caching for batch sends
  • Errors 131051, 131052, and 131053 are the most common — handle them explicitly in your code

With the helper function presented above, you have a unified interface that validates size, detects the media type, and routes to the correct flow — ready to integrate into any Node.js application.

Artigos Relacionados

  • APIs & Integrações

    Como Enviar Imagens, Vídeos e Documentos pela WhatsApp Business API

  • APIs & Integrações

    Template WhatsApp Rejeitado ou Pausado: Como Entender e Corrigir

  • APIs & Integrações

    Como Criar e Gerenciar Templates na WhatsApp Business API: Guia Completo

.