Documentação oficial para integração com nossa plataforma de SMS
Todas as requisições devem usar a seguinte URL base:
https://zucpay.com/api/v1/
Todas as requisições (exceto endpoints públicos) devem incluir suas credenciais de API nos headers:
X-API-Key: sua_api_key X-API-Secret: seu_api_secret
Suas credenciais podem ser geradas no painel do cliente em API Keys.
curl -X GET "https://zucpay.com/api/v1/balance" \ -H "X-API-Key: sua_api_key" \ -H "X-API-Secret: seu_api_secret"
{
"success": true,
"data": {
"balance": 1250.50,
"blocked": 50.00,
"available": 1200.50,
"currency": "BRL",
"limit": 0
},
"timestamp": 1704067200
}
| Parâmetro | Tipo | Descrição | Exemplo |
|---|---|---|---|
| country | string | Filtrar por país (código numérico) | 73 (Brasil) |
| service | string | Filtrar por serviço específico | wa (WhatsApp) |
| operator | string | Filtrar por operadora | claro, vivo |
| available | boolean | Apenas serviços com estoque | true |
| provider | string | Filtrar por provedor | provedor 2, provedor 1 |
GET https://zucpay.com/api/v1/services?country=73&available=true
{
"success": true,
"data": [
{
"country_id": "73",
"country_name": "Brasil",
"services": [
{ "code": "wa", "name": "WhatsApp", "operator": "claro", "price": 2.50, "stock": 150, "provider": "provedor 1" },
{ "code": "tg", "name": "Telegram", "operator": "vivo", "price": 1.80, "stock": 75, "provider": "provedor 2" }
]
}
],
"timestamp": 1704067200
}
| Campo | Tipo | Obrigatório | Descrição | Exemplo |
|---|---|---|---|---|
| service | string | sim | Código do serviço | "wa" |
| country | string | sim | Código do país | "73" |
| operator | string | não | Operadora específica | "claro" |
| max_price | float | não | Preço máximo em BRL | 5.00 |
| request_id | string | não | ID único para evitar duplicatas | "req_123456" |
request_id para garantir que a mesma compra não seja processada múltiplas vezes em caso de falhas de rede.
{
"service": "wa",
"country": "73",
"operator": "claro",
"max_price": 5.00,
"request_id": "req_1784822251"
}
{
"success": true,
"data": {
"activation_id": "ACT17040672001234",
"phone": "5511999999999",
"operator": "claro",
"price": 2.50,
"currency": "BRL",
"request_id": "req_123456"
},
"timestamp": 1704067200
}
| Parâmetro | Obrigatório | Descrição |
|---|---|---|
| activation_id | sim | ID da ativação recebido na compra |
| Status | Descrição |
|---|---|
pending | Aguardando recebimento do SMS |
received | SMS recebido com sucesso |
canceled | Ativação cancelada |
expired | Tempo limite excedido (20 minutos) |
{
"success": true,
"data": {
"activation_id": "ACT17040672001234",
"status": "pending",
"phone": "5511999999999",
"created_at": 1704067200
},
"timestamp": 1704067260
}
{
"success": true,
"data": {
"activation_id": "ACT17040672001234",
"status": "received",
"code": "123456",
"phone": "5511999999999",
"created_at": 1704067200,
"received_at": 1704067260
},
"timestamp": 1704067260
}
{ "activation_id": "ACT17040672001234" }
{
"success": true,
"data": {
"activation_id": "ACT17040672001234",
"status": "canceled",
"refunded": true
},
"timestamp": 1704067260
}
Configure webhooks para receber notificações em tempo real sobre eventos da sua conta.
| Evento | Descrição |
|---|---|
sms.received | Disparado quando um SMS é recebido |
sms.purchased | Disparado quando um número é comprado |
balance.low | Disparado quando o saldo está abaixo do limite (R$ 50) |
{
"event": "sms.received",
"url": "https://seu-dominio.com/webhook/sms",
"secret": "seu_secret_opcional"
}
{
"event": "sms.received",
"timestamp": 1704067200,
"data": {
"activation_id": "ACT17040672001234",
"code": "123456",
"phone": "5511999999999",
"service": "wa"
}
}
{ "webhook_id": 1 }
<?php
/**
* Cliente para API SMS Provider
* Requisitos: PHP 7.4+, cURL, JSON
*/
class SMSProviderClient {
private $apiKey;
private $apiSecret;
private $baseUrl;
public function __construct($apiKey, $apiSecret, $baseUrl = 'https://zucpay.com/api/v1') {
$this->apiKey = $apiKey;
$this->apiSecret = $apiSecret;
$this->baseUrl = rtrim($baseUrl, '/');
}
private function request($endpoint, $method = 'GET', $data = null) {
$ch = curl_init($this->baseUrl . $endpoint);
$headers = [ 'X-API-Key: ' . $this->apiKey, 'X-API-Secret: ' . $this->apiSecret, 'Content-Type: application/json' ];
curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => $headers, CURLOPT_CUSTOMREQUEST => $method, CURLOPT_TIMEOUT => 30, CURLOPT_SSL_VERIFYPEER => true ]);
if ($data) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (curl_error($ch)) throw new Exception('Erro cURL: ' . curl_error($ch));
curl_close($ch);
$result = json_decode($response, true);
if (!$result || !isset($result['success'])) throw new Exception('Resposta inválida da API');
if ($httpCode !== 200 || !$result['success']) {
$error = $result['error'] ?? 'Erro desconhecido';
throw new Exception($error, $httpCode);
}
return $result['data'] ?? $result;
}
public function getBalance() { return $this->request('/balance'); }
public function getServices($filters = []) {
$query = http_build_query($filters);
return $this->request('/services?' . $query);
}
public function buyNumber($service, $country, $operator = null, $maxPrice = null, $requestId = null) {
$data = [ 'service' => $service, 'country' => $country ];
if ($operator) $data['operator'] = $operator;
if ($maxPrice) $data['max_price'] = $maxPrice;
if ($requestId) $data['request_id'] = $requestId;
return $this->request('/buy', 'POST', $data);
}
public function checkStatus($activationId) { return $this->request('/status?activation_id=' . urlencode($activationId)); }
public function cancelActivation($activationId) { return $this->request('/cancel', 'POST', ['activation_id' => $activationId]); }
public function registerWebhook($event, $url, $secret = null) {
$data = ['event' => $event, 'url' => $url];
if ($secret) $data['secret'] = $secret;
return $this->request('/webhook', 'POST', $data);
}
public function listWebhooks() { return $this->request('/webhook'); }
public function deleteWebhook($webhookId) { return $this->request('/webhook', 'DELETE', ['webhook_id' => $webhookId]); }
}
try {
$client = new SMSProviderClient('sua_api_key', 'seu_api_secret');
$balance = $client->getBalance();
echo "Saldo disponível: R$ " . number_format($balance['available'], 2, ',', '.') . "\n";
$services = $client->getServices(['country' => '73', 'available' => true]);
foreach ($services as $country) {
echo "\nPaís: {$country['country_name']}\n";
foreach ($country['services'] as $service) {
echo " - {$service['name']}: R$ " . number_format($service['price'], 2, ',', '.') . " (estoque: {$service['stock']})\n";
}
}
$requestId = 'req_' . time();
$result = $client->buyNumber('wa', '73', 'claro', 5.00, $requestId);
echo "\nNúmero comprado: {$result['phone']}\nActivation ID: {$result['activation_id']}\n";
} catch (Exception $e) { echo "Erro: " . $e->getMessage() . "\n"; }
?>
import requests
from typing import Optional, Dict
class SMSProviderClient:
def __init__(self, api_key: str, api_secret: str, base_url: str = 'https://zucpay.com/api/v1'):
self.api_key = api_key
self.api_secret = api_secret
self.base_url = base_url.rstrip('/')
self.session = requests.Session()
self.session.headers.update({ 'X-API-Key': api_key, 'X-API-Secret': api_secret, 'Content-Type': 'application/json' })
def _request(self, endpoint: str, method: str = 'GET', data: Dict = None) -> Dict:
url = f"{self.base_url}{endpoint}"
try:
response = self.session.request(method, url, json=data, timeout=30)
response.raise_for_status()
result = response.json()
if not result.get('success'): raise Exception(result.get('error', 'Erro desconhecido'))
return result.get('data', result)
except requests.exceptions.RequestException as e: raise Exception(f"Erro na requisição: {str(e)}")
def get_balance(self) -> Dict: return self._request('/balance')
def get_services(self, country: str = None, service: str = None, operator: str = None, available: bool = None) -> Dict:
params = {}
if country: params['country'] = country
if service: params['service'] = service
if operator: params['operator'] = operator
if available: params['available'] = 'true'
query = '&'.join([f"{k}={v}" for k, v in params.items()])
endpoint = f"/services?{query}" if query else "/services"
return self._request(endpoint)
def buy_number(self, service: str, country: str, operator: str = None, max_price: float = None, request_id: str = None) -> Dict:
data = { 'service': service, 'country': country }
if operator: data['operator'] = operator
if max_price: data['max_price'] = max_price
if request_id: data['request_id'] = request_id
return self._request('/buy', 'POST', data)
def check_status(self, activation_id: str) -> Dict: return self._request(f"/status?activation_id={activation_id}")
def cancel_activation(self, activation_id: str) -> Dict: return self._request('/cancel', 'POST', {'activation_id': activation_id})
def register_webhook(self, event: str, url: str, secret: str = None) -> Dict:
data = {'event': event, 'url': url}
if secret: data['secret'] = secret
return self._request('/webhook', 'POST', data)
def list_webhooks(self) -> Dict: return self._request('/webhook')
def delete_webhook(self, webhook_id: int) -> Dict: return self._request('/webhook', 'DELETE', {'webhook_id': webhook_id})
if __name__ == '__main__':
try:
client = SMSProviderClient('sua_api_key', 'seu_api_secret')
balance = client.get_balance()
print(f"Saldo disponível: R$ {balance['available']:.2f}")
services = client.get_services(country='73', available=True)
for country in services:
print(f"\nPaís: {country['country_name']}")
for service in country['services']:
print(f" - {service['name']}: R$ {service['price']:.2f} (estoque: {service['stock']})")
except Exception as e: print(f"Erro: {e}")
const axios = require('axios');
class SMSProviderClient {
constructor(apiKey, apiSecret, baseUrl = 'https://zucpay.com/api/v1') {
this.apiKey = apiKey;
this.apiSecret = apiSecret;
this.baseUrl = baseUrl.replace(/\/$/, '');
this.client = axios.create({
baseURL: this.baseUrl,
timeout: 30000,
headers: { 'X-API-Key': apiKey, 'X-API-Secret': apiSecret, 'Content-Type': 'application/json' }
});
}
async _request(endpoint, method = 'GET', data = null) {
try {
const response = await this.client.request({ url: endpoint, method, data });
if (!response.data.success) throw new Error(response.data.error || 'Erro desconhecido');
return response.data.data || response.data;
} catch (error) {
if (error.response) throw new Error(error.response.data.error || `HTTP ${error.response.status}`);
throw error;
}
}
async getBalance() { return this._request('/balance'); }
async getServices(filters = {}) {
const params = new URLSearchParams(filters).toString();
const endpoint = params ? `/services?${params}` : '/services';
return this._request(endpoint);
}
async buyNumber(service, country, operator = null, maxPrice = null, requestId = null) {
const data = { service, country };
if (operator) data.operator = operator;
if (maxPrice) data.max_price = maxPrice;
if (requestId) data.request_id = requestId;
return this._request('/buy', 'POST', data);
}
async checkStatus(activationId) { return this._request(`/status?activation_id=${encodeURIComponent(activationId)}`); }
async cancelActivation(activationId) { return this._request('/cancel', 'POST', { activation_id: activationId }); }
async registerWebhook(event, url, secret = null) {
const data = { event, url };
if (secret) data.secret = secret;
return this._request('/webhook', 'POST', data);
}
async listWebhooks() { return this._request('/webhook'); }
async deleteWebhook(webhookId) { return this._request('/webhook', 'DELETE', { webhook_id: webhookId }); }
}
async function main() {
try {
const client = new SMSProviderClient('sua_api_key', 'seu_api_secret');
const balance = await client.getBalance();
console.log(`Saldo disponível: R$ ${balance.available.toFixed(2)}`);
const services = await client.getServices({ country: '73', available: true });
services.forEach(country => {
console.log(`\nPaís: ${country.country_name}`);
country.services.forEach(service => {
console.log(` - ${service.name}: R$ ${service.price.toFixed(2)} (estoque: ${service.stock})`);
});
});
} catch (error) { console.error('Erro:', error.message); }
}
main();
#!/bin/bash
API_KEY="sua_api_key"
API_SECRET="seu_api_secret"
BASE_URL="https://zucpay.com/api/v1"
echo "📊 Consultando saldo..."
curl -s -X GET "$BASE_URL/balance" -H "X-API-Key: $API_KEY" -H "X-API-Secret: $API_SECRET" | jq '.'
echo -e "\n📋 Listando serviços do Brasil..."
curl -s -X GET "$BASE_URL/services?country=73&available=true" -H "X-API-Key: $API_KEY" -H "X-API-Secret: $API_SECRET" | jq '.'
echo -e "\n🛒 Comprando número WhatsApp..."
REQUEST_ID="req_$(date +%s)"
curl -s -X POST "$BASE_URL/buy" -H "X-API-Key: $API_KEY" -H "X-API-Secret: $API_SECRET" -H "Content-Type: application/json" -d "{\"service\":\"wa\",\"country\":\"73\",\"operator\":\"claro\",\"max_price\":5.00,\"request_id\":\"$REQUEST_ID\"}" | jq '.'
ACTIVATION_ID="ACT123456"
echo -e "\n🔍 Verificando status..."
curl -s -X GET "$BASE_URL/status?activation_id=$ACTIVATION_ID" -H "X-API-Key: $API_KEY" -H "X-API-Secret: $API_SECRET" | jq '.'
echo -e "\n🔔 Registrando webhook..."
curl -s -X POST "$BASE_URL/webhook" -H "X-API-Key: $API_KEY" -H "X-API-Secret: $API_SECRET" -H "Content-Type: application/json" -d '{"event":"sms.received","url":"https://meu-site.com/webhook/sms","secret":"meu_secret_123"}' | jq '.'
class SMSProviderClient {
constructor(apiKey, apiSecret, baseUrl = 'https://zucpay.com/api/v1') {
this.apiKey = apiKey;
this.apiSecret = apiSecret;
this.baseUrl = baseUrl.replace(/\/$/, '');
}
async request(endpoint, method = 'GET', data = null) {
const url = `${this.baseUrl}${endpoint}`;
const headers = { 'X-API-Key': this.apiKey, 'X-API-Secret': this.apiSecret, 'Content-Type': 'application/json' };
const options = { method, headers, mode: 'cors' };
if (data) options.body = JSON.stringify(data);
const response = await fetch(url, options);
const result = await response.json();
if (!response.ok || !result.success) throw new Error(result.error || `HTTP ${response.status}`);
return result.data || result;
}
async getBalance() { return this.request('/balance'); }
async getServices(filters = {}) {
const params = new URLSearchParams(filters).toString();
const endpoint = params ? `/services?${params}` : '/services';
return this.request(endpoint);
}
async buyNumber(service, country, operator = null, maxPrice = null, requestId = null) {
const data = { service, country };
if (operator) data.operator = operator;
if (maxPrice) data.max_price = maxPrice;
if (requestId) data.request_id = requestId;
return this.request('/buy', 'POST', data);
}
async checkStatus(activationId) { return this.request(`/status?activation_id=${encodeURIComponent(activationId)}`); }
async cancelActivation(activationId) { return this.request('/cancel', 'POST', { activation_id: activationId }); }
}
async function exemplo() {
try {
const client = new SMSProviderClient('sua_api_key', 'seu_api_secret');
const balance = await client.getBalance();
console.log('Saldo:', balance);
const services = await client.getServices({ country: '73' });
console.log('Serviços:', services);
} catch (error) { console.error('Erro:', error.message); }
}
| Código | Significado | Descrição | Solução |
|---|---|---|---|
| 400 | Bad Request | Parâmetros inválidos ou ausentes | Verifique os campos obrigatórios |
| 401 | Unauthorized | API Key ou Secret inválidos | Verifique suas credenciais |
| 402 | Payment Required | Saldo insuficiente | Recarregue sua conta |
| 403 | Forbidden | Sem permissão para o recurso | Verifique as permissões da chave |
| 404 | Not Found | Recurso não encontrado | Verifique o endpoint e parâmetros |
| 405 | Method Not Allowed | Método HTTP inválido | Use GET/POST conforme documentado |
| 409 | Conflict | Request ID já utilizado | Use um request_id único |
| 429 | Too Many Requests | Limite de requisições excedido | Aguarde e reduza a frequência |
| 500 | Internal Server Error | Erro interno do servidor | Tente novamente ou contate o suporte |
Cada chave de API tem um limite de requisições por minuto (configurável no painel).
Os headers de resposta incluem informações sobre o rate limit:
X-RateLimit-Limit: 60 X-RateLimit-Remaining: 58 X-RateLimit-Reset: 1704067260
Para garantir que os webhooks são realmente enviados por nossa API, você pode verificar a assinatura:
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$secret = 'seu_secret_configurado';
$expected = hash_hmac('sha256', $payload, $secret);
if (hash_equals($expected, $signature)) {
$data = json_decode($payload, true);
} else {
http_response_code(401);
exit;
}