> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wyzecash.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK para PHP

> O pacote oficial wyzecash/wyzecash para PHP 8.1+: cobranças, saques, subcontas e webhooks, só com cURL, e com a integração para o Laravel.

O `wyzecash/wyzecash` é o SDK oficial da WyzeCash para **PHP 8.1+**. Ele fala com a mesma API da documentação, só que com listas que passam de página sozinhas, novas tentativas seguras, a conferência dos webhooks e a integração com o Laravel prontas.

> [card] Só cURL e JSON
>
> As extensões que já vêm na maioria das hospedagens. A conexão é reaproveitada entre os pedidos.

> [card] Campos no editor
>
> O formato de cada pedido e resposta vem nos comentários: o PhpStorm e o PHPStan completam e avisam.

> [card] Seguro com dinheiro
>
> O que tira dinheiro nunca é repetido sozinho.

> [!WARNING]
>
> Use o SDK **só no servidor**. A chave de API vai em todo pedido: nunca a coloque em JavaScript do site, app ou repositório.

## Instalar

```bash theme={null}
composer require wyzecash/wyzecash
```

## Começar

**1. Crie a chave de API**

No painel, em **Integrações e API › Chaves de API**, crie uma chave `bk_live_…` só com as permissões que o seu sistema usa (ex.: `/payments/create` e `/payments/get`).

**2. Guarde a chave no ambiente**

```bash .env theme={null}
WYZECASH_API_KEY=bk_live_...
```

Sem passar a chave no código, o SDK lê a variável `WYZECASH_API_KEY`.

**3. Crie a primeira cobrança**

```php theme={null}
<?php
require 'vendor/autoload.php';

use WyzeCash\WyzeCash;

$wyzecash = new WyzeCash(getenv('WYZECASH_API_KEY'));

$cobranca = $wyzecash->payments->create(
    ['amount' => 15000, 'description' => 'Pedido 1052'], // R$ 150,00, sempre em centavos
    ['idempotencyKey' => 'pedido-1052'],                 // o código do pedido no seu sistema
);

echo $cobranca['id'];        // BKY-...
echo $cobranca['copyPaste']; // Pix Copia e Cola (vira QR Code)
```

**4. Receba o aviso de pago**

Pelo [webhook](#webhooks). Libere o pedido só no `payment.paid`.

> [!NOTE]
>
> Não existe ambiente de testes: todo pedido é de verdade. Para testar, faça uma cobrança pequena e pague com o seu banco.

## Campos e respostas

Os campos vão num array, com **os mesmos nomes da API** (`subaccountId`, `feePaidBy`, `cryptoCurrency`...), então os exemplos da [Referência da API](https://docs.wyzecash.com.br/referencia/visao-geral.md) valem direto. As respostas voltam como arrays.

* Os códigos vão antes dos campos: `$wyzecash->subaccounts->fund('vendedor-42', ['amount' => 1000])`.
* O último parâmetro de cada método são as opções: `idempotencyKey`, `timeout` e `maxRetries`.
* Campo com `null` vai como `null`, que em alguns campos limpa o valor: `'limits' => ['perWithdrawal' => null]` tira o limite próprio da subconta.

## Configurar o cliente

```php theme={null}
$wyzecash = new WyzeCash(getenv('WYZECASH_API_KEY'), [
    'timeout' => 60,    // tempo máximo de cada pedido, em segundos (padrão 60)
    'maxRetries' => 2,  // novas tentativas quando é seguro (padrão 2)
]);
```

| Opção | Padrão | O que faz |
| - | - | - |
| a chave (1º parâmetro) | a variável `WYZECASH_API_KEY` | A chave `bk_live_…` |
| `timeout` | `60` | Tempo máximo de cada pedido, em segundos |
| `maxRetries` | `2` | Quantas vezes tentar de novo quando é seguro |
| `baseUrl` | o endereço da API | Só para casos especiais (proxy) |
| `transport` | cURL | Outro jeito de fazer o pedido HTTP (testes ou proxy), com a interface `WyzeCash\Http\Transport` |

## Recursos

Os métodos seguem as rotas da API. Cada um precisa da permissão daquela rota na chave.

| Recurso | Métodos | Rotas |
| - | - | - |
| `payments` | `create`, `methods`, `list`, `retrieve` | [Cobranças](https://docs.wyzecash.com.br/endpoints/cobrancas.md) |
| `paymentLinks` | `create`, `list`, `retrieve`, `update`, `delete`, `listPayments` | [Links de pagamento](https://docs.wyzecash.com.br/endpoints/links-de-pagamento.md) |
| `customers` | `create`, `list`, `retrieve`, `update`, `delete` | [Clientes](https://docs.wyzecash.com.br/endpoints/clientes.md) |
| `balance` | `retrieve` | [Saldo e tarifas](https://docs.wyzecash.com.br/endpoints/saldo.md) |
| `fees` | `list`, `preview` | [Saldo e tarifas](https://docs.wyzecash.com.br/endpoints/saldo.md) |
| `statement` | `list` | [Extrato](https://docs.wyzecash.com.br/endpoints/transacoes.md) |
| `transactions` | `list`, `retrieve` | [Extrato](https://docs.wyzecash.com.br/endpoints/transacoes.md) |
| `search` | `query` | [Extrato](https://docs.wyzecash.com.br/endpoints/transacoes.md) |
| `receipts` | `retrieve` | [Saques](https://docs.wyzecash.com.br/endpoints/saques.md) |
| `withdrawals` | `create`, `list`, `retrieve` | [Saques](https://docs.wyzecash.com.br/endpoints/saques.md) |
| `refunds` | `create`, `list`, `retrieve` | [Cobranças](https://docs.wyzecash.com.br/endpoints/cobrancas.md) |
| `meds` | `list`, `retrieve`, `respond` | [MED](https://docs.wyzecash.com.br/endpoints/med.md) |
| `subaccounts` | `create`, `list`, `retrieve`, `update`, `delete`, `retrieveSettings`, `updateSettings`, `previewSettings`, `listEntries`, `fund`, `transfer`, `returnToAccount`, `withdraw` | [Subcontas](https://docs.wyzecash.com.br/endpoints/subcontas.md) |

## Exemplos

> [tab] Pix
>
> ```php theme={null}
> $cobranca = $wyzecash->payments->create(
>     ['amount' => 4990, 'description' => 'Assinatura de novembro', 'customerId' => '0d6c1a7e-...'],
>     ['idempotencyKey' => 'assinatura-2026-11-cliente-81'],
> );
>
> enviarParaCliente($cobranca['copyPaste']); // mostre o QR Code ou o texto para copiar
> ```
>
> O Pix vale 30 minutos (`expiresAt`).

> [tab] Cartão
>
> ```php theme={null}
> $cobranca = $wyzecash->payments->create(
>     ['amount' => 15000, 'method' => 'card', 'description' => 'Pedido 1053'],
>     ['idempotencyKey' => 'pedido-1053'],
> );
>
> header('Location: ' . $cobranca['paymentUrl']); // página segura de pagamento
> ```
>
> O número do cartão nunca passa pelo seu servidor. A venda aprovada fica "A liberar" até `availableAt`.

> [tab] Cripto
>
> ```php theme={null}
> $cobranca = $wyzecash->payments->create(
>     ['amount' => 20000, 'method' => 'crypto', 'cryptoCurrency' => 'sol'],
>     ['idempotencyKey' => 'pedido-1054'],
> );
>
> print_r($cobranca['crypto']); // moeda, valor na moeda e endereço
> ```
>
> A cotação vale 10 minutos.

> [tab] Cliente paga a tarifa
>
> ```php theme={null}
> $cobranca = $wyzecash->payments->create(['amount' => 10000, 'feePaidBy' => 'payer'], ['idempotencyKey' => 'pedido-1055']);
>
> echo $cobranca['total'];     // o que o cliente paga (valor + tarifa)
> echo $cobranca['netAmount']; // o que entra para você (o valor inteiro)
> ```

> [tab] Saque
>
> ```php theme={null}
> $saque = $wyzecash->withdrawals->create(
>     ['amount' => 10000, 'destination' => ['keyType' => 'email', 'key' => 'financeiro@exemplo.com']],
>     ['idempotencyKey' => 'saque-2026-11-05'],
> );
>
> echo $saque['status']; // "processing": confirme pelo webhook withdrawal.completed
> ```
>
> A chave precisa da permissão `/withdrawals/create`, que pede o 2FA ligado na conta ao criar a chave.

> [tab] Estorno
>
> ```php theme={null}
> $estorno = $wyzecash->refunds->create(
>     ['transactionId' => 'BKY-7KQ2M9XP4RZT', 'amount' => 5000, 'reason' => 'Produto devolvido'],
>     ['idempotencyKey' => 'estorno-pedido-1052'],
> );
> ```
>
> Estorno só no Pix. Sem `amount`, devolve tudo o que ainda não foi devolvido.

## Listas

A lista traz **a primeira página**. O `foreach` passa por **todas**, buscando a próxima só quando precisa.

```php theme={null}
// Só a primeira página
$pagina = $wyzecash->payments->list(['status' => 'paid', 'limit' => 50]);
echo count($pagina->items), ' ', $pagina->nextCursor;

// Todas, uma de cada vez
foreach ($wyzecash->payments->list(['status' => 'paid']) as $cobranca) {
    echo $cobranca['id'], ' ', $cobranca['amount'], PHP_EOL;
}

// Numa lista só (cuidado com contas grandes)
$ultimas = $wyzecash->statement->list()->toArray(200);
```

`$pagina->nextPage()` busca só a próxima, e `$pagina['totals']` lê os outros campos da resposta (como os totais do extrato).

## Idempotency-Key

Criar cobrança, saque, estorno e os envios das subcontas pedem a `Idempotency-Key`. Passe **o código do pedido no seu sistema**: repetir a mesma chave devolve o mesmo resultado, sem fazer de novo.

```php theme={null}
$wyzecash->withdrawals->create(
    ['amount' => 10000, 'destination' => ['keyType' => 'cpf', 'key' => '12345678900']],
    ['idempotencyKey' => 'saque-1052'],
);
```

> [!TIP]
>
> Sem a chave, o SDK cria uma por chamada: protege a nova tentativa automática, mas não protege você de chamar duas vezes. Em dinheiro saindo, passe sempre a sua.

## Erros e novas tentativas

Todo erro da API vira um `WyzeCashException`:

```php theme={null}
use WyzeCash\Exception\ConnectionException;
use WyzeCash\Exception\WyzeCashException;

try {
    $wyzecash->payments->create(['amount' => 15000], ['idempotencyKey' => 'pedido-1056']);
} catch (ConnectionException $erro) {
    // A resposta não voltou (rede ou tempo esgotado): confira antes de tentar de novo.
} catch (WyzeCashException $erro) {
    error_log("{$erro->status} {$erro->errorCode} {$erro->getMessage()} {$erro->requestId}");
}
```

| Campo | O que é |
| - | - |
| `status` | A situação HTTP (`0` quando o pedido nem chegou à API) |
| `errorCode` | Código estável para o seu sistema: `VALIDATION`, `INSUFFICIENT_FUNDS`, `RATE_LIMITED`... (veja [Erros](https://docs.wyzecash.com.br/erros.md)) |
| `getMessage()` | O motivo em português |
| `requestId` | O código do pedido: mande para o suporte quando precisar de ajuda |
| `details` | Detalhes, quando a API manda (ex.: qual campo está errado) |

O SDK tenta de novo sozinho só quando é seguro:

| Situação | Tenta de novo? |
| - | - |
| `429` (passou de 100 pedidos por minuto) | Sim, esperando o `Retry-After` |
| Erro de rede ou `5xx` numa consulta ou ao criar cobrança | Sim |
| Saque, estorno e envios das subcontas | **Nunca.** Se a rede cair, confira pela consulta ou pelo webhook antes de pedir de novo |
| `4xx` (dado errado, sem saldo, sem permissão) | Não: corrija o pedido |

## Webhooks

Cada aviso chega com o cabeçalho `X-Bukio-Signature`. Confira **com o corpo cru**, do jeito que chegou, antes do `json_decode`:

> [tab] PHP puro
>
> ```php webhook.php theme={null}
> <?php
> require 'vendor/autoload.php';
>
> use WyzeCash\Exception\WebhookException;
> use WyzeCash\Webhook;
>
> try {
>     $evento = Webhook::verify(
>         file_get_contents('php://input'),
>         $_SERVER['HTTP_X_BUKIO_SIGNATURE'] ?? null,
>         getenv('WYZECASH_WEBHOOK_SECRET'),
>     );
> } catch (WebhookException) {
>     http_response_code(400);
>     exit;
> }
>
> if ($evento['type'] === 'payment.paid') {
>     liberarPedido($evento['data']); // use $evento['id'] para não processar duas vezes
> }
> http_response_code(200);
> ```

> [tab] Laravel
>
> O SDK já traz o middleware `wyzecash.webhook`: ele confere a assinatura com o segredo do `.env` e o aviso que não é da WyzeCash recebe `400` sem chegar à sua rota.
>
> ```php routes/api.php theme={null}
> use Illuminate\Http\Request;
> use Illuminate\Support\Facades\Route;
>
> Route::post('/webhooks/wyzecash', function (Request $request) {
>     $evento = $request->attributes->get('wyzecash_event');
>
>     if ($evento['type'] === 'payment.paid') {
>         LiberarPedido::dispatch($evento['data']); // fila: responda logo, processe depois
>     }
>     return response()->json(['received' => true]);
> })->middleware('wyzecash.webhook');
> ```
>
> Rotas em `routes/api.php` não passam pela proteção de CSRF. Se usar `routes/web.php`, tire a rota da verificação de CSRF.

| Erro (`WebhookException`, em `errorCode`) | Quando |
| - | - |
| `MISSING_SIGNATURE` | O aviso veio sem o cabeçalho `X-Bukio-Signature` |
| `INVALID_SIGNATURE` | Assinatura errada ou em formato errado |
| `TIMESTAMP_OUT_OF_RANGE` | Assinado há mais de 5 minutos (mude com o 4º parâmetro, em segundos) |
| `INVALID_PAYLOAD` | O corpo não é um evento válido |

Responda `2xx` em até 10 segundos. O segredo `whsec_…` fica em **Integrações e API › Webhooks**. Veja [Validando a assinatura](https://docs.wyzecash.com.br/webhooks/assinatura.md) e a [lista de eventos](https://docs.wyzecash.com.br/webhooks/configurar.md).

## Laravel

O provider entra sozinho (package discovery). No `.env`:

```bash .env theme={null}
WYZECASH_API_KEY=bk_live_...
WYZECASH_WEBHOOK_SECRET=whsec_...
```

Receba o cliente por injeção, em qualquer controller, job ou comando:

```php theme={null}
use WyzeCash\WyzeCash;

final class CobrancaController
{
    public function store(WyzeCash $wyzecash)
    {
        $cobranca = $wyzecash->payments->create(
            ['amount' => 15000, 'description' => 'Pedido 1052'],
            ['idempotencyKey' => 'pedido-1052'],
        );

        return ['id' => $cobranca['id'], 'copyPaste' => $cobranca['copyPaste']];
    }
}
```

Para mudar o tempo dos pedidos ou as novas tentativas, publique a configuração: `php artisan vendor:publish --tag=wyzecash-config` (cria o `config/wyzecash.php`).

## Tempo real

Em PHP, receba os eventos pelos [webhooks](https://docs.wyzecash.com.br/webhooks/configurar.md): o PHP roda melhor respondendo pedidos. Se precisar de um processo que fica ligado (um bot, por exemplo), o protocolo está em [WebSocket](https://docs.wyzecash.com.br/webhooks/websocket.md) e funciona com qualquer biblioteca de WebSocket.

## Onde roda

| Ambiente | Funciona? |
| - | - |
| PHP 8.1, 8.2, 8.3 e 8.4 com `curl` e `json` | Sim |
| Laravel, Symfony, WordPress e PHP puro | Sim |
| JavaScript do site ou app | **Não use**: a chave de API ficaria exposta |

O código do SDK é aberto: [github.com/wamberg236-cmd/wyzecash-php](https://github.com/wamberg236-cmd/wyzecash-php).

## Próximos passos

* [Sua primeira cobrança](https://docs.wyzecash.com.br/inicio-rapido.md) e [Antes de ir para produção](https://docs.wyzecash.com.br/producao.md).
* Todas as rotas, com os campos: [Referência da API](https://docs.wyzecash.com.br/referencia/visao-geral.md).
* Também há SDK oficial para [Node.js](https://docs.wyzecash.com.br/sdk/node.md) e [Python](https://docs.wyzecash.com.br/sdk/python.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.