POST/withdraw (também disponível como GET, mesmos parâmetros via query string)
Cria uma solicitação de saque. Depois de criada, envie os tokens DePix necessários para o depositAddress retornado, na Liquid Network. Consulte o status periodicamente via /withdraw/status. Limite de taxa: 30 requisições por minuto (verificado ao vivo em 19/07/2026 — versões anteriores desta documentação diziam 60/min, incorretamente).
Saques são bloqueados quando pending_cents >= 1000 (R$ 10,00) de taxas pendentes acumuladas. O objeto fee_info, presente em toda resposta de criação de saque, informa o status atual (ok, warning, danger, blocked ou credit) e os valores em centavos: credit_cents, pending_cents, gross_fee_cents, paid_cents e limit_cents (sempre 1000).
As mensagens legíveis em message são traduzidas via o header Accept-Language (en é o padrão quando nenhum header é enviado; pt e es também disponíveis). Os exemplos abaixo mostram o texto em inglês (padrão).
Parâmetros
| Campo | Tipo | Obrigatório | Descrição |
code | string | Sim | Seu código de integração (API). |
pixKey | string | Sim | Chave PIX (CPF, CNPJ, e-mail, telefone ou chave aleatória/EVP) de destino do pagamento. |
pixKeyType | string (cpf, cnpj, phone, email, evp, other) | Não | Determina como pixKey é normalizada/validada (ex.: cpf precisa ter 11 dígitos; phone é normalizado para E.164 +55...). Default: other se omitido. |
taxNumber | string | Condicional | CPF/CNPJ do recebedor, somente dígitos. Preenchido automaticamente a partir de pixKey quando pixKeyType é cpf/cnpj. Nos demais casos, é obrigatório pelo PSP a menos que a conta já tenha um CPF verificado cadastrado — se faltar, o erro é "at least one of 'taxNumber' or 'euid' params must be set". |
depositAmountInCents | integer | Um dos dois* | Valor em centavos de DePix a depositar. Fornecer OU este OU payoutAmountInCents, nunca os dois. Faixa do PSP: 200–600000 (R$ 2,00–R$ 6.000,00). |
payoutAmountInCents | integer | Um dos dois* | Valor em centavos de PIX a receber. Fornecer OU este OU depositAmountInCents, nunca os dois. Mesma faixa do PSP. |
Resposta de sucesso (200)
Resposta real, capturada em produção (saque de R$ 10,00 em DePix, 19/07/2026). Note que o campo de ID é withdrawalId (não id como em versões anteriores desta documentação), e que a resposta de criação não inclui id, pixKey, assetId ou expiration — só os 4 campos abaixo:
{
"success": true,
"message": "Withdraw created successfully",
"data": {
"response": {
"depositAddress": "lq1qqguzpzl4wj4vpuveuajlvnvadf79g67s2pwd6cf38gcysf0aqh3mk4590lxrk03d83sk3v25fyvd4st3unnw7t70qpycvmsd9",
"depositAmountInCents": 1000,
"payoutAmountInCents": 900,
"withdrawalId": "019f7bd8aa48797ab862e5ca8bf5d8e6"
},
"async": false
},
"fee_info": {
"status": "ok",
"message": "Pending fee: R$ 0,10. Blocking occurs when reaching R$ 10.00. To add credits and avoid blocks, go to https://BlackRocket/withdraws and add credits.",
"is_blocked": false,
"credit_cents": 0,
"pending_cents": 10,
"gross_fee_cents": 10,
"paid_cents": 0,
"limit_cents": 1000
},
"additional_fee_message": "This withdrawal exceeds the available amount without fee. The standard fee of 1% from PleBank/DePix plus 1% platform fee will be applied, totaling 2% fee on the excess amount."
}
additional_fee_message só aparece quando o saque excede o valor disponível sem taxa, indicando que uma taxa adicional será aplicada. Use withdrawalId para consultar o status em /withdraw/status.
Resposta bloqueada (403)
{
"success": false,
"message": "Withdraw blocked. Please pay the pending fees to continue. To add credits and avoid blocks, go to https://BlackRocket/withdraws and add credits.",
"fee_info": {
"status": "blocked",
"message": "Withdrawals blocked. Pay R$ 10.50 in pending fees to unlock. To add credits and avoid blocks, go to https://BlackRocket/withdraws and add credits.",
"is_blocked": true,
"credit_cents": 0,
"pending_cents": 1050,
"gross_fee_cents": 1050,
"paid_cents": 0,
"limit_cents": 1000
}
}
Erros
| Status | Quando ocorre |
| 403 | Saque bloqueado — taxas pendentes ≥ R$ 10,00 (veja acima). |
| 422 | Erro de validação. Exemplos reais da API (em inglês, padrão): "Invalid code" (em português com Accept-Language: pt: "Código inválido"), "Either depositAmountInCents or payoutAmountInCents must be provided", "Only one of depositAmountInCents or payoutAmountInCents can be provided", "Invalid CPF. Use 11 digits.", "Invalid email.". |
| ⚠️ não padrão (ex.: 520) | Quando o PSP upstream rejeita a requisição, a API repassa o status HTTP do próprio PSP, que pode não ser um código padrão. Verificado ao vivo retornando HTTP 520 tanto para falta de taxNumber/EUID quanto para valor fora da faixa 200–600000. Corpo típico: {"success": false, "message": "Failed to create withdraw", "error": {"response": {"errorMessage": "at least one of 'taxNumber' or 'euid' params must be set"}, "async": false}}. Não assuma que apenas códigos 4xx/5xx padrão são possíveis — trate pelo corpo JSON. |
| 429 | Limite de 30 requisições/minuto excedido. |
| 500 | Erro inesperado na nossa aplicação (ex.: falha de rede ao chamar o PSP). |
Exemplos de código
cURL
curl -X POST "https://blackrocket.space/api/withdraw" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"code": "SEU_CODIGO",
"pixKey": "00550235175",
"pixKeyType": "cpf",
"depositAmountInCents": 1000
}'
PHP
<?php
// Envie EXATAMENTE UM de depositAmountInCents OU payoutAmountInCents, nunca os dois.
// Faixa imposta pelo PSP: 200 a 600000 centavos (R$ 2,00 a R$ 6.000,00).
$payload = [
'code' => 'SEU_CODIGO',
'pixKey' => '00550235175',
'pixKeyType' => 'cpf', // cpf, cnpj, phone, email, evp ou other (default: other)
'depositAmountInCents' => 1000,
// 'taxNumber' => '00550235175', // obrigatório pelo PSP quando pixKeyType não é cpf/cnpj
// // e a conta não tem CPF verificado
];
$ch = curl_init('https://blackrocket.space/api/withdraw');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Accept: application/json'],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$data = json_decode($response, true);
if ($httpCode === 403) {
// Saque bloqueado por taxas pendentes — veja $data['fee_info']
} elseif ($httpCode >= 400) {
// O PSP upstream pode retornar um status HTTP não padrão (ex.: 520) quando rejeita a
// requisição (faixa de valor inválida, taxNumber/euid ausente). Trate pelo corpo JSON,
// não apenas pelo código HTTP.
echo $data['message'] ?? $data['error']['response']['errorMessage'] ?? 'erro desconhecido';
} else {
// Envie os tokens DePix para $data['data']['response']['depositAddress']
echo $data['data']['response']['withdrawalId'];
}
JavaScript (fetch)
const response = await fetch('https://blackrocket.space/api/withdraw', {
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify({
code: 'SEU_CODIGO',
pixKey: '00550235175',
pixKeyType: 'cpf', // cpf, cnpj, phone, email, evp ou other (default: other)
depositAmountInCents: 1000,
// taxNumber: '00550235175', // obrigatório pelo PSP quando pixKeyType não é cpf/cnpj
}),
});
const data = await response.json();
if (response.status === 403) {
// Saque bloqueado por taxas pendentes — veja data.fee_info
} else if (!response.ok) {
// O PSP pode devolver um status HTTP não padrão (ex.: 520). Verifique o corpo JSON.
console.error(data.message ?? data.error?.response?.errorMessage);
} else {
// Envie os tokens DePix para data.data.response.depositAddress
console.log(data.data.response.withdrawalId);
}
TypeScript
interface WithdrawRequest {
code: string;
pixKey: string;
pixKeyType?: 'cpf' | 'cnpj' | 'phone' | 'email' | 'evp' | 'other'; // default: 'other'
taxNumber?: string; // CPF/CNPJ do recebedor — obrigatório pelo PSP em vários casos
depositAmountInCents?: number; // 200–600000 (R$ 2,00–R$ 6.000,00)
payoutAmountInCents?: number;
}
interface FeeInfo {
status: 'ok' | 'warning' | 'danger' | 'blocked' | 'credit';
message: string;
is_blocked: boolean;
credit_cents: number;
pending_cents: number;
gross_fee_cents: number;
paid_cents: number;
limit_cents: number;
}
interface WithdrawCreateResponse {
success: boolean;
message: string;
data: {
response: {
depositAddress: string;
depositAmountInCents: number;
payoutAmountInCents: number;
withdrawalId: string; // note: withdrawalId aqui, mas "id" em /withdraw/status
};
async: boolean;
};
fee_info: FeeInfo;
additional_fee_message?: string;
}
const payload: WithdrawRequest = {
code: 'SEU_CODIGO',
pixKey: '00550235175',
pixKeyType: 'cpf',
depositAmountInCents: 1000,
};
const response = await fetch('https://blackrocket.space/api/withdraw', {
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify(payload),
});
const data: WithdrawCreateResponse = await response.json();
Python (requests)
import requests
# Envie EXATAMENTE UM de deposit_amount_in_cents OU payout_amount_in_cents, nunca os dois.
# Faixa imposta pelo PSP: 200 a 600000 centavos (R$ 2,00 a R$ 6.000,00).
payload = {
"code": "SEU_CODIGO",
"pixKey": "00550235175",
"pixKeyType": "cpf", # cpf, cnpj, phone, email, evp ou other (default: other)
"depositAmountInCents": 1000,
# "taxNumber": "00550235175", # obrigatório pelo PSP quando pixKeyType não é cpf/cnpj
}
response = requests.post(
"https://blackrocket.space/api/withdraw",
json=payload,
headers={"Accept": "application/json"},
)
data = response.json()
if response.status_code == 403:
# Saque bloqueado por taxas pendentes — veja data["fee_info"]
pass
elif not response.ok:
# O PSP pode devolver um status HTTP não padrão (ex.: 520). Verifique o corpo JSON.
print(data.get("message") or data.get("error", {}).get("response", {}).get("errorMessage"))
else:
# Envie os tokens DePix para data["data"]["response"]["depositAddress"]
print(data["data"]["response"]["withdrawalId"])
Java (java.net.http)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
String json = """
{
"code": "SEU_CODIGO",
"pixKey": "00550235175",
"pixKeyType": "cpf",
"depositAmountInCents": 1000
}""";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://blackrocket.space/api/withdraw"))
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
// Em caso de sucesso, o ID do saque vem em data.response.withdrawalId (não "id").
// O PSP pode devolver códigos HTTP não padrão (ex.: 520) em rejeições — trate pelo corpo JSON.
GET/withdraw/status (também disponível como POST, com id no corpo JSON)
Consulta o status de uma solicitação de saque pelo seu ID (o withdrawalId retornado na criação). Este é o status bruto do PSP — valores observados ao vivo incluem pending, unsent, processing, sending, completed, sent, failed, expired. Trate status como uma string aberta, não um enum fixo, já que o PSP pode introduzir novos valores. Intervalo de verificação recomendado: a cada 10 minutos. Limite de taxa: 30 requisições por minuto (verificado ao vivo — versões anteriores desta documentação diziam 60/min, incorretamente).
Diferente dos demais endpoints de saque, este não exige o parâmetro code — apenas o id retornado na criação da solicitação.
Este vocabulário de status é diferente e mais granular do que o vocabulário normalizado retornado em /withdraw/history — veja o aviso na seção abaixo.
Parâmetros
| Campo | Tipo | Obrigatório | Descrição |
id | string | Sim | ID do saque (withdrawalId) retornado na criação da solicitação. |
Resposta de sucesso (200)
Resposta real, capturada em produção logo após a criação do saque (19/07/2026) — aqui o campo de ID é id (diferente de withdrawalId na criação):
{
"success": true,
"data": {
"response": {
"depositAddress": "lq1qqguzpzl4wj4vpuveuajlvnvadf79g67s2pwd6cf38gcysf0aqh3mk4590lxrk03d83sk3v25fyvd4st3unnw7t70qpycvmsd9",
"depositAmountInCents": 1000,
"expiration": "2026-07-20T19:27:04Z",
"id": "019f7bd8aa48797ab862e5ca8bf5d8e6",
"payoutAmountInCents": 900,
"pixKey": "00550235175",
"status": "unsent"
},
"async": false
},
"receipt_url": null,
"has_api_receipt": false
}
blockchainTxID aparece (não nulo) quando o processamento na blockchain já começou. receipt_url é preenchido quando o saque é concluído e um recibo imprimível foi gerado; has_api_receipt espelha essa disponibilidade.
Erros
| Status | Quando ocorre |
| ⚠️ não padrão (ex.: 520) | ID inválido/inexistente ou erro do PSP — a API repassa o status HTTP do próprio PSP. Verificado ao vivo: HTTP 520 com corpo {"success": false, "message": "Failed to check status", "error": {"response": {"errorMessage": "invalid id"}, "async": false}}. |
| 429 | Limite de 30 requisições/minuto excedido. |
Exemplos de código
cURL
curl -G "https://blackrocket.space/api/withdraw/status" \
-H "Accept: application/json" \
--data-urlencode "id=019f7bd8aa48797ab862e5ca8bf5d8e6"
PHP
<?php
$id = '019f7bd8aa48797ab862e5ca8bf5d8e6';
$ch = curl_init("https://blackrocket.space/api/withdraw/status?" . http_build_query(['id' => $id]));
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Accept: application/json'],
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
// status é uma string aberta, não um enum fixo. Valores observados ao vivo:
// pending, unsent, processing, sending, completed, sent, failed, expired.
$status = $data['data']['response']['status'];
echo $status;
JavaScript (fetch)
const params = new URLSearchParams({ id: '019f7bd8aa48797ab862e5ca8bf5d8e6' });
const response = await fetch(`https://blackrocket.space/api/withdraw/status?${params}`, {
headers: { Accept: 'application/json' },
});
const data = await response.json();
// status é uma string aberta, não um enum fixo. Valores observados ao vivo:
// pending, unsent, processing, sending, completed, sent, failed, expired.
console.log(data.data.response.status);
TypeScript
// status é uma string aberta (a PSP pode introduzir novos valores) — não trate como enum fechado.
type WithdrawStatus = string;
interface WithdrawStatusResponse {
success: boolean;
data: {
response: {
id: string;
pixKey: string;
depositAmountInCents: number;
payoutAmountInCents: number;
depositAddress: string;
blockchainTxID?: string | null;
status: WithdrawStatus;
expiration: string;
};
async: boolean;
};
receipt_url: string | null;
has_api_receipt: boolean;
}
const params = new URLSearchParams({ id: '019f7bd8aa48797ab862e5ca8bf5d8e6' });
const response = await fetch(`https://blackrocket.space/api/withdraw/status?${params}`, {
headers: { Accept: 'application/json' },
});
const data: WithdrawStatusResponse = await response.json();
Python (requests)
import requests
response = requests.get(
"https://blackrocket.space/api/withdraw/status",
params={"id": "019f7bd8aa48797ab862e5ca8bf5d8e6"},
headers={"Accept": "application/json"},
)
data = response.json()
# status é uma string aberta, não um enum fixo. Valores observados ao vivo:
# pending, unsent, processing, sending, completed, sent, failed, expired.
print(data["data"]["response"]["status"])
Java (java.net.http)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://blackrocket.space/api/withdraw/status?id=019f7bd8aa48797ab862e5ca8bf5d8e6"))
.header("Accept", "application/json")
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
// status é string aberta: pending, unsent, processing, sending, completed, sent, failed, expired.
GET/withdraw/history (também disponível como POST, com code no corpo JSON)
⚠️ Achado importante — este endpoint não funciona como chamada de API stateless. Apesar de estar sob /api/withdraw/history e de aceitar um parâmetro code, a implementação real do controller (WithdrawController::history) autentica via auth()->user() — ou seja, via sessão de login do navegador — e não via code/lookup de PermanentLink como todos os demais endpoints /withdraw*. Uma chamada real com um code válido e sem sessão autenticada retornou 403 {"success": false, "message": "Unauthorized"}. Na prática, este endpoint só funciona vindo de uma sessão de navegador já autenticada no dashboard /withdraws — não é possível integrá-lo como chamada de API pura usando apenas code. O parâmetro code é aceito sem erro pela API, mas atualmente não tem nenhum efeito na resposta. Se o acesso ao histórico via code for necessário para integrações de parceiros, é preciso sinalizar isso à engenharia — não é o comportamento atual.
Quando chamado a partir de uma sessão autenticada, a visibilidade depende do papel do usuário logado: Admin vê todos os saques; Manager vê os saques dos usuários dos seus grupos; Analyst/Normal vê apenas os próprios saques. Saques não pagos com mais de 24 horas são excluídos do histórico; saques pagos ficam disponíveis para sempre. Limite de taxa: 30 requisições por minuto (verificado ao vivo — versões anteriores desta documentação diziam 60/min, incorretamente).
O campo status aqui usa um vocabulário normalizado interno (pending, processing, sending, completed, failed, expired) — menor e diferente do status bruto do PSP retornado por /withdraw/status. Nunca inclui sent; esse valor bruto do PSP é normalizado para completed aqui.
Parâmetros
| Campo | Tipo | Obrigatório | Descrição |
code | string | Não | Aceito pela API, mas atualmente sem efeito — veja o aviso ⚠️ acima. A autenticação real é por sessão de navegador. |
Resposta de sucesso (200) — apenas via sessão autenticada
{
"success": true,
"show_user_column": true,
"data": [
{
"id": "019c8c1dfd537434a2a14f0aa1c64011",
"pix_key": "user@example.com",
"deposit_amount_cents": 10000,
"payout_amount_cents": 9900,
"status": "completed",
"created_at": "2026-02-26T12:00:00+00:00",
"updated_at": "2026-02-26T12:05:00+00:00",
"can_show_receipt": true,
"user_id": 123,
"user_display": "John Doe"
}
]
}
show_user_column é true quando as informações de usuário (user_id, user_display) estão incluídas — normalmente para papéis Admin e Manager. can_show_receipt é true quando status é completed.
Resposta sem sessão autenticada (403) — verificado ao vivo
{
"success": false,
"message": "Unauthorized"
}
Erros
| Status | Quando ocorre |
| 403 | Sem sessão autenticada, ou perfil do usuário logado não é admin/manager/analyst. Ocorre mesmo enviando um code válido, conforme verificado ao vivo. |
| 429 | Limite de 30 requisições/minuto excedido. |
Exemplos de código
cURL
# ATENÇÃO: este endpoint autentica via sessão de login do navegador (auth()->user()),
# não via `code`. Uma chamada stateless como esta, sem cookie de sessão, retorna 403
# mesmo com um `code` válido. Veja o aviso na seção abaixo.
curl -G "https://blackrocket.space/api/withdraw/history" \
-H "Accept: application/json" \
--data-urlencode "code=SEU_CODIGO"
# -> 403 {"success": false, "message": "Unauthorized"}
PHP
<?php
// ATENÇÃO: /withdraw/history autentica via sessão de login (auth()->user()), não via
// `code`. Este exemplo reproduz uma chamada stateless — ela retorna 403, mesmo com
// um `code` válido, porque não há sessão de navegador autenticada. Veja o aviso ⚠️
// na página sobre este endpoint. Ele só funciona a partir do dashboard /withdraws,
// vindo de um navegador já logado.
$code = 'SEU_CODIGO';
$ch = curl_init("https://blackrocket.space/api/withdraw/history?" . http_build_query(['code' => $code]));
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Accept: application/json'],
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 403) {
// Esperado sem sessão autenticada: {"success": false, "message": "Unauthorized"}
exit;
}
$data = json_decode($response, true);
foreach ($data['data'] as $withdraw) {
echo "{$withdraw['id']}: {$withdraw['status']} ({$withdraw['payout_amount_cents']} centavos)\n";
}
JavaScript (fetch)
// ATENÇÃO: /withdraw/history autentica via sessão de login (auth()->user()), não via
// `code`. Sem um cookie de sessão de navegador autenticado, isto retorna 403 mesmo
// com um `code` válido. Só funciona vindo do dashboard /withdraws logado.
const params = new URLSearchParams({ code: 'SEU_CODIGO' });
const response = await fetch(`https://blackrocket.space/api/withdraw/history?${params}`, {
headers: { Accept: 'application/json' },
});
if (response.status === 403) {
// Esperado sem sessão autenticada: {"success": false, "message": "Unauthorized"}
} else {
const { data } = await response.json();
for (const withdraw of data) {
console.log(withdraw.id, withdraw.status, withdraw.payout_amount_cents);
}
}
TypeScript
interface WithdrawHistoryEntry {
id: string;
pix_key: string;
deposit_amount_cents: number;
payout_amount_cents: number;
// Vocabulário normalizado interno — diferente do status bruto do PSP em /withdraw/status.
// Nunca inclui "sent" (é normalizado para "completed").
status: 'pending' | 'processing' | 'sending' | 'completed' | 'failed' | 'expired';
created_at: string;
updated_at: string;
can_show_receipt: boolean;
user_id?: number;
user_display?: string;
}
interface WithdrawHistoryResponse {
success: boolean;
show_user_column: boolean;
data: WithdrawHistoryEntry[];
}
// ATENÇÃO: autenticado via sessão de login (auth()->user()), não via `code` — veja o
// aviso ⚠️ na página. Sem sessão de navegador, a chamada abaixo retorna 403.
const params = new URLSearchParams({ code: 'SEU_CODIGO' });
const response = await fetch(`https://blackrocket.space/api/withdraw/history?${params}`, {
headers: { Accept: 'application/json' },
});
const { data }: WithdrawHistoryResponse = await response.json();
Python (requests)
# ATENÇÃO: /withdraw/history autentica via sessão de login (auth()->user()), não via
# `code`. Sem um cookie de sessão de navegador autenticado, retorna 403 mesmo com um
# `code` válido. Só funciona a partir de uma sessão de browser logada no dashboard
# /withdraws — não é utilizável como chamada de API stateless.
import requests
response = requests.get(
"https://blackrocket.space/api/withdraw/history",
params={"code": "SEU_CODIGO"},
headers={"Accept": "application/json"},
)
if response.status_code == 403:
print("Esperado sem sessão autenticada:", response.json())
else:
data = response.json()["data"]
for withdraw in data:
print(withdraw["id"], withdraw["status"], withdraw["payout_amount_cents"])
Java (java.net.http)
// ATENÇÃO: /withdraw/history autentica via sessão de login (auth()->user()), não via
// `code` — veja o aviso ⚠️ na página. Uma chamada stateless como esta retorna 403.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://blackrocket.space/api/withdraw/history?code=SEU_CODIGO"))
.header("Accept", "application/json")
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
// Esperado sem sessão de navegador autenticada: 403 {"success": false, "message": "Unauthorized"}