curl --request GET \
--url https://api.zapsterapi.com/v1/wa/recipients/{recipient}/pp \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.zapsterapi.com/v1/wa/recipients/{recipient}/pp"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.zapsterapi.com/v1/wa/recipients/{recipient}/pp', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.zapsterapi.com/v1/wa/recipients/{recipient}/pp",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.zapsterapi.com/v1/wa/recipients/{recipient}/pp"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.zapsterapi.com/v1/wa/recipients/{recipient}/pp")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.zapsterapi.com/v1/wa/recipients/{recipient}/pp")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"url": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"expires_at": "2026-01-15T12:00:00.000Z"
}{
"errors": [
{
"code": "recipient_invalid_format",
"message": "The recipient must be a phone number in international format (e.g. 5511999999999)."
}
]
}{
"errors": [
{
"code": "invalid_signature",
"message": "The profile picture URL signature is missing, invalid or expired. Fetch the recipient again to get a fresh URL."
}
]
}{
"errors": [
{
"code": "recipient_not_found",
"message": "The specified recipient could not be found."
}
]
}{
"errors": [
{
"code": "rate_limited",
"message": "You can only make 10 recipient checks every 60 seconds."
}
]
}{
"errors": [
{
"code": "recipient_pool_unavailable",
"message": "The recipient verification service is temporarily unavailable. Please try again shortly."
}
]
}Foto de Perfil do Destinatário
Retorna a foto de perfil de um número, por redirecionamento (302) ou como JSON.
curl --request GET \
--url https://api.zapsterapi.com/v1/wa/recipients/{recipient}/pp \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.zapsterapi.com/v1/wa/recipients/{recipient}/pp"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.zapsterapi.com/v1/wa/recipients/{recipient}/pp', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.zapsterapi.com/v1/wa/recipients/{recipient}/pp",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.zapsterapi.com/v1/wa/recipients/{recipient}/pp"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.zapsterapi.com/v1/wa/recipients/{recipient}/pp")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.zapsterapi.com/v1/wa/recipients/{recipient}/pp")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"url": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"expires_at": "2026-01-15T12:00:00.000Z"
}{
"errors": [
{
"code": "recipient_invalid_format",
"message": "The recipient must be a phone number in international format (e.g. 5511999999999)."
}
]
}{
"errors": [
{
"code": "invalid_signature",
"message": "The profile picture URL signature is missing, invalid or expired. Fetch the recipient again to get a fresh URL."
}
]
}{
"errors": [
{
"code": "recipient_not_found",
"message": "The specified recipient could not be found."
}
]
}{
"errors": [
{
"code": "rate_limited",
"message": "You can only make 10 recipient checks every 60 seconds."
}
]
}{
"errors": [
{
"code": "recipient_pool_unavailable",
"message": "The recipient verification service is temporarily unavailable. Please try again shortly."
}
]
}Introdução
Este endpoint serve a foto de perfil de um número do WhatsApp a partir de uma URL estável. É a URL retornada no campoprofile_picture da Verificação de Número (Sem Instância) e da sua versão em lote: ela não expira como uma URL assinada de storage, então pode ser armazenada e reutilizada — a cada acesso, a API resolve a foto mais recente disponível.
429 com o código rate_limited e o header Retry-After indica quando tentar de novo.Como funciona
Por padrão, a resposta é um redirecionamento302 para uma URL assinada temporária da imagem (validade de 10 minutos). Isso significa que a URL funciona diretamente onde um navegador resolve redirecionamentos por conta própria:
<img src="https://api.zapsterapi.com/v1/wa/recipients/5511999999999/pp" />
?mode=json:
curl "https://api.zapsterapi.com/v1/wa/recipients/5511999999999/pp?mode=json"
{
"url": "https://zapsterapi.s3.us-east-1.amazonaws.com/...",
"expires_at": "2026-01-15T12:00:00.000Z"
}
expires_at para o momento exato e solicite uma nova URL quando expirar. Qualquer outro valor de mode é tratado como o padrão (redirecionamento). Quando o número não tem foto disponível, o modo JSON responde { "url": null }.
Sem foto: placeholder
Este endpoint funciona de forma independente: não é preciso consultar o número antes nos endpoints de verificação. Um número que existe no WhatsApp mas está sem foto disponível (foto privada ou nenhuma foto atribuída) — ou que não está no WhatsApp — não retorna erro por padrão: o parâmetroplaceholder controla a resposta.
placeholder | Resposta |
|---|---|
omitido ou 1 | 200 com um avatar genérico em SVG (Cache-Control: public, max-age=86400) |
0 | 404 com o código recipient_not_found |
uma URL https | 302 redirecionando para a URL informada — sirva seu próprio placeholder |
<img src="https://api.zapsterapi.com/v1/wa/recipients/5511999999999/pp?placeholder=https%3A%2F%2Fmeusite.com%2Favatar.png" />
placeholder inválida (não-https, longa demais) é tratada como o padrão (avatar genérico). O mode=json ignora o placeholder e responde { "url": null }.
Assinatura da URL (opcional)
As URLs deprofile_picture retornadas pelos endpoints de verificação podem vir com os parâmetros exp e sig, que assinam a URL com prazo de validade. Quando a exigência de assinatura está habilitada na plataforma, uma requisição sem assinatura válida retorna 403 com o código invalid_signature — basta consultar o destinatário novamente para receber uma URL nova. Você não precisa montar (nem entender) esses parâmetros: use a URL exatamente como ela foi retornada.
Pontos de Atenção
profile_picture retornadas pelos endpoints de verificação sempre apontam para este endpoint, mesmo quando o número não tem foto — nesse caso, a resposta é o placeholder descrito acima. Para saber se um número tem foto de fato, use ?mode=json e verifique se url é null.<img src>. Para exibir muitas fotos com frequência, prefira o ?mode=json e reutilize a URL assinada enquanto ela for válida.Autorizações
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Parâmetros de caminho
Número do destinatário em formato internacional (E.164), com ou sem o + inicial.
Parâmetros de consulta
Comportamento quando o número não tem foto disponível. Omitido ou 1, a resposta é 200 com um avatar genérico em SVG; 0 retorna 404 com o código recipient_not_found; uma URL https retorna 302 redirecionando para ela (útil para servir um placeholder próprio). Ignorado quando mode=json.
Formato da resposta. Use json para receber a URL assinada num corpo JSON em vez do redirecionamento 302. Qualquer outro valor é tratado como o padrão (redirecionamento).
json Expiração da assinatura da URL (epoch em segundos). Presente nas URLs retornadas pelos endpoints de verificação quando a assinatura está habilitada; não precisa ser montado manualmente.
Assinatura da URL. Presente nas URLs retornadas pelos endpoints de verificação quando a assinatura está habilitada; não precisa ser montada manualmente.
Resposta
Resposta em JSON quando mode=json é informado, ou o avatar genérico em SVG quando o número não tem foto disponível (comportamento padrão do placeholder).
URL assinada temporária da imagem. null quando o número não tem foto disponível (o mode=json ignora o parâmetro placeholder).
"https://zapsterapi.s3.us-east-1.amazonaws.com/..."
Momento em que a URL assinada expira (ISO 8601). Presente apenas quando url não é null.
"2026-01-15T12:00:00.000Z"