Processing your request, please wait...

    Referência da API — Saques

    Endpoints /withdraw, /withdraw/status e /withdraw/history, com exemplos em 6 linguagens

    Sobre esta referência

    Esta página documenta os endpoints de saque, que convertem tokens DePix recebidos na sua carteira Liquid Network em um pagamento PIX enviado a uma chave PIX de destino. Todos os campos, exemplos de resposta e mensagens de erro abaixo foram verificados ao vivo contra a API de produção em 19/07/2026 e batem com a especificação OpenAPI usada em produção (/api-docs, versão 3.5).

    ⚠️ Sempre envie o header Accept: application/json. Sem ele, uma falha de validação de parâmetro obrigatório retorna um redirect HTML 302 em vez de um erro JSON. Todos os exemplos de código abaixo já enviam esse header.

    Em POST /withdraw (e no equivalente GET), forneça exatamente um dos parâmetros depositAmountInCents (quanto de DePix você vai depositar — a taxa é somada por cima) ou payoutAmountInCents (quanto de PIX o destinatário deve receber — a taxa é descontada desse valor). Enviar os dois ao mesmo tempo, ou nenhum dos dois, resulta em erro 422. O valor informado (em qualquer um dos dois campos) precisa estar entre 200 e 600.000 centavos (R$ 2,00 a R$ 6.000,00) — faixa imposta pelo PSP upstream.

    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

    CampoTipoObrigatórioDescrição
    codestringSimSeu código de integração (API).
    pixKeystringSimChave PIX (CPF, CNPJ, e-mail, telefone ou chave aleatória/EVP) de destino do pagamento.
    pixKeyTypestring (cpf, cnpj, phone, email, evp, other)NãoDetermina como pixKey é normalizada/validada (ex.: cpf precisa ter 11 dígitos; phone é normalizado para E.164 +55...). Default: other se omitido.
    taxNumberstringCondicionalCPF/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".
    depositAmountInCentsintegerUm 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).
    payoutAmountInCentsintegerUm 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

    StatusQuando ocorre
    403Saque bloqueado — taxas pendentes ≥ R$ 10,00 (veja acima).
    422Erro 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.
    429Limite de 30 requisições/minuto excedido.
    500Erro 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

    CampoTipoObrigatórioDescrição
    idstringSimID 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

    StatusQuando 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}}.
    429Limite 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

    CampoTipoObrigatórioDescrição
    codestringNãoAceito 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

    StatusQuando ocorre
    403Sem 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.
    429Limite 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"}

    Próximos passos