Search by

enricodias / paghiper

A PHP client for the PagHiper API (Boleto, PIX, withdrawals and nota fiscal) with typed request builders, response models and proper exception handling.

Maintainers

Package info

github.com/enricodias/paghiper-php

pkg:composer/enricodias/paghiper

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-07-03 04:08 UTC

This package is auto-updated.

Last update: 2026-08-23 22:57:29 UTC


README

A complete PHP client for the PagHiper API with typed request builders, response models, and proper exception handling.

Supports: boleto, PIX, transaction listing, bank account withdrawals, and nota fiscal.

Requirements

  • PHP 7.3 or higher
  • Composer
  • A PSR-18 HTTP client and PSR-17 factories (e.g. Guzzle)

Installation

composer require enricodias/paghiper

This package does not include an HTTP client. Install one alongside it. Guzzle is the most common choice:

composer require guzzlehttp/guzzle

Setup

use PagHiper\Client;

$client = new Client('your-api-key', 'your-token');

Your apiKey and token are available in your PagHiper panel.

HTTP client

Any PSR-18 compatible client works. The client is auto-discovered at runtime via php-http/discovery, so no additional configuration is needed as long as a supported client is installed.

If you already use a PSR-18 client in your project, you can pass it directly to avoid auto-discovery:

$client = new Client('your-api-key', 'your-token', $yourHttpClient);

The PSR-17 request and stream factories are also auto-discovered. If you want to provide your own, you can also pass them directly:

$client = new Client('your-api-key', 'your-token', $yourHttpClient, null, $requestFactory, $streamFactory);

Boleto

Create

use PagHiper\Type\BankSlipType;

$transaction = $client->boleto()->create()
    ->orderId('ORD-001')
    ->payer('João Silva', 'joao@example.com', '00000000191')
    ->daysDueDate(5)
    ->bankSlipType(BankSlipType::a4())
    ->addItem('1', 'Produto A', 2, 1500)
    ->addItem('2', 'Produto B', 1, 3000)
    ->send();

echo $transaction->transactionId(); // HF97T5SH2ZKVKR3K
echo $transaction->bankSlip()->digitableLine();
echo $transaction->bankSlip()->urlSlip();

Optional fields:

$client->boleto()->create()
    ->orderId('ORD-001')
    ->payer('João Silva', 'joao@example.com', '00000000191')
    ->daysDueDate(5)
    ->bankSlipType(BankSlipType::a4())
    ->addItem('1', 'Produto A', 1, 9900)
    ->payerPhone('11987654321')
    ->payerStreet('Rua das Flores')->payerNumber('42')->payerDistrict('Centro')
    ->payerCity('São Paulo')->payerState('SP')->payerZipCode('01310100')
    ->notificationUrl('https://mysite.com/webhooks/paghiper')
    ->discountCents(500)
    ->shippingPriceCents(1000)
    ->latePaymentFine(2)
    ->perDayInterest()
    ->earlyPaymentDiscountsDays(3)->earlyPaymentDiscountsCents(200)
    ->openAfterDayDue(10)
    ->send();

Status

$transaction = $client->boleto()->status('HF97T5SH2ZKVKR3K');

echo $transaction->status()->value();       // "paid"
$transaction->status()->isPaid();           // true
$transaction->status()->isFinal();          // true
echo $transaction->valueCents()->toReais(); // "R$ 60,00"

Cancel

$result = $client->boleto()->cancel('HF97T5SH2ZKVKR3K');

echo $result->responseMessage();

Webhook notifications

PagHiper POSTs to your notification_url when a transaction's status changes. Your endpoint must respond with HTTP 200. Use the responder to parse the payload, confirm receipt to PagHiper, and get the full transaction details in one call:

// In your webhook endpoint:
$transaction = $client->boleto()->notifications()->confirm($_POST);

echo $transaction->status()->value();
echo $transaction->payerName();
echo $transaction->valueCentsPaid()?->cents();

If you want to inspect or validate the notification before confirming (e.g. to check the apiKey matches your own):

use PagHiper\Module\Boleto\Notification\BoletoNotificationParser;

$parser = new BoletoNotificationParser();
$notification = $parser->parse($_POST);

if ($notification->apiKey() !== 'apk_your-api-key') {
    http_response_code(403);
    exit;
}

$transaction = $client->boleto()->notifications()->confirmNotification($notification);

PIX

Create

$transaction = $client->pix()->create()
    ->orderId('ORD-002')
    ->payer('Maria Souza', 'maria@example.com', '00000000272')
    ->daysDueDate(1)
    ->addItem('1', 'Produto A', 1, 9900)
    ->send();

echo $transaction->transactionId();
echo $transaction->pixCode()->qrCodeBase64(); // base64 PNG for display
echo $transaction->pixCode()->emv();          // EMV code for copy & paste
$transaction->pixCode()->toBinary();          // raw PNG bytes to save to disk

Use minutesDueDate() instead of daysDueDate() for short-lived charges:

$client->pix()->create()
    ->orderId('ORD-002')
    ->payer('Maria Souza', 'maria@example.com', '00000000272')
    ->minutesDueDate(30)
    ->addItem('1', 'Produto A', 1, 9900)
    ->send();

Status

Some fields are not present in the response after a Pix is paid.

$transaction = $client->pix()->status('BPV661O7AVLORCN5');

$transaction->status()->isPaid(); // true
$transaction->pixCode()->emv();   // null

Cancel

$result = $client->pix()->cancel('BPV661O7AVLORCN5');

Refund

PIX refunds are subject to PagHiper's business rules: the transaction must be paid, the refund must be requested within 60 days of the payment date, and your account must have sufficient balance. If any condition is not met, a RequestRejectedException is thrown with the reason.

$result = $client->pix()->refund('BPV661O7AVLORCN5');

echo $result->responseMessage();

Webhook notifications

// In your webhook endpoint:
$transaction = $client->pix()->notifications()->confirm($_POST);

echo $transaction->status()->value();
echo $transaction->payerName();

Transaction listing

Lists both boleto and PIX transactions. All filters are optional.

use PagHiper\Type\DateFilterFieldType;
use PagHiper\Type\TransactionStatusType;
use PagHiper\Type\ValueCentsFilterOperatorType;

$page = $client->transactions()->list()
    ->status(TransactionStatusType::paid())
    ->initialDate('2024-01-01')
    ->finalDate('2024-01-31')
    ->filterDate(DateFilterFieldType::paid())
    ->limit(50)
    ->send();

echo $page->currentPage(); // 1
echo $page->totalPages();  // 4
$page->hasMorePages();     // true

foreach ($page->items() as $item) {
    echo $item->transactionId();
    echo $item->orderId();
    echo $item->status()->value();
    echo $item->valueCents()->toReais();

    if ($item->isBoleto()) {
        echo $item->bankSlip()->digitableLine();
    }

    if ($item->isPix()) {
        echo $item->pixCode()->qrCodeBase64();
    }
}

To page through all results:

$page = 1;

do {
    $result = $client->transactions()->list()
        ->status(TransactionStatusType::paid())
        ->limit(100)
        ->page($page)
        ->send();

    foreach ($result->items() as $item) {
        // process $item
    }

    $page++;
} while ($result->hasMorePages());

When a query matches no transactions, an empty page is returned rather than throwing an exception. $page->isEmpty() will be true and $page->items() will be [].

Available filters: status(), initialDate(), finalDate(), filterDate(), dueDate(), payerCpfCnpj(), orderId(), valueCents(), limit() (1–100), page() (1–999).

filterDate() is required by PagHiper whenever initialDate() or finalDate() is set. Valid values: DateFilterFieldType::created(), DateFilterFieldType::paid(), DateFilterFieldType::due().

Bank accounts and withdrawals

Withdrawals always transfer your entire available balance to the selected account. There is no partial withdrawal option.

// List registered bank accounts eligible for withdrawal:
$accounts = $client->bankAccounts()->list();

foreach ($accounts as $account) {
    echo $account->bankAccountId(); // integer, use this to withdraw
    echo $account->bankName();      // "Itaú"
    echo $account->bankCode();      // "341"
    echo $account->accountType();   // "Corrente"
}

// Withdraw full available balance to a specific account:
$result = $client->bankAccounts()->withdraw($accounts[0]->bankAccountId());

echo $result->responseMessage();

Nota fiscal

Lists the last 24 fee invoices PagHiper has issued to your account. These are PagHiper's billing documents for the fees they charge you, not customer-facing invoices for your own orders.

$invoices = $client->notaFiscal()->list();

foreach ($invoices as $invoice) {
    echo $invoice->invoiceId();
    echo $invoice->invoiceDate();                  // "Y-m-d"
    echo $invoice->invoiceValueCents()->toReais(); // "R$ 1,23"
    echo $invoice->invoiceUrl();                   // link to the NF-e document
    echo $invoice->invoiceType();                  // "tarifa"
    echo $invoice->invoiceDescription();           // fee calculation breakdown
}

For invoices older than the last 24, contact PagHiper support.

Exception handling

All exceptions extend PagHiper\Exception\PagHiperException, so you can catch broadly or granularly:

use PagHiper\Exception\HttpException;
use PagHiper\Exception\PagHiperException;
use PagHiper\Exception\RateLimitedException;
use PagHiper\Exception\RequestRejectedException;
use PagHiper\Exception\ValidationException;

try {
    $transaction = $client->boleto()->create()
        ->orderId('ORD-001')
        ->payer('João Silva', 'joao@example.com', '00000000191')
        ->daysDueDate(5)
        ->bankSlipType(BankSlipType::a4())
        ->addItem('1', 'Produto A', 1, 9900)
        ->send();
} catch (ValidationException $e) {
    // A required field was missing or invalid before any HTTP call was made.
    echo $e->getMessage();
} catch (RateLimitedException $e) {
    // HTTP 429, back off and retry after a delay.
} catch (RequestRejectedException $e) {
    // PagHiper accepted the request but rejected it for a business reason.
    echo $e->getResponseMessage();  // e.g. "token não informado ou invalido"

    // Check for a specific known reason:
    if ($e->messageContains('prazo de reembolso')) {
        // handle expired refund window
    }
} catch (HttpException $e) {
    // Network error, non-2xx HTTP status, or malformed response body.
    echo $e->getStatusCode();
    echo $e->getResponseBody();
} catch (PagHiperException $e) {
    // Catch-all for anything else from this package.
}

Exception reference

Exception When thrown
ValidationException Required field missing or invalid, before any HTTP call
RequestRejectedException PagHiper returns "result": "reject" (HTTP 200)
RateLimitedException HTTP 429 too many requests
HttpException Network error, non-2xx status, or malformed/empty response body
UnexpectedResponseException HTTP 2xx + "result": "success" but a required field is missing from the response

JSON serialization

All transaction response classes implement JsonSerializable, so they can be passed directly to json_encode(). All monetary values are serialized as integer cents.

$transaction = $client->boleto()->status('HF97T5SH2ZKVKR3K');

$json = \json_encode($transaction);
// or, to get the array directly:
$data = $transaction->jsonSerialize();

The same applies to PixTransaction and TransactionListItem. This is useful for storing transaction snapshots for audit or logging purposes.

Money values

All monetary values are represented as Money objects, which wrap the raw cents integer PagHiper returns:

$money = $transaction->valueCents();

$money->cents();   // 9900  (int)
$money->toFloat(); // 99.0  (float)
$money->toReais(); // "R$ 99,00"  (formatted string)

Logging

Pass any PSR-3 compatible logger as the fourth argument. Monolog is a common choice:

composer require monolog/monolog
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$logger = new Logger('paghiper');
$logger->pushHandler(new StreamHandler('/var/log/paghiper.log'));

$client = new Client('apk_your-api-key', 'your-token', null, $logger);

When a logger is provided, the following events are recorded:

Event Level When
PagHiper request debug Before each outgoing request (credentials redacted)
PagHiper response debug After each successful response
PagHiper rejected request warning PagHiper returns "result": "reject"
PagHiper rate limit exceeded warning HTTP 429
PagHiper unexpected HTTP status error Non-2xx HTTP status
PagHiper network error error Connection failure
PagHiper transport error error Other HTTP client error

License

MIT