Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Paghiper For Laravel Laravel Package

devajmeireles/paghiper-for-laravel

Seamless Laravel integration for PagHiper, the Brazilian payment gateway, letting you quickly generate boleto and PIX charges, manage transactions, and handle payment notifications directly within your PHP applications through a clean, fluent API.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and configure

composer require devajmeireles/paghiper-for-laravel
php artisan vendor:publish --tag="paghiper-config"

Add credentials to .env (names follow the published config; typical keys are PAGHIPER_API_KEY and PAGHIPER_TOKEN, plus a sandbox toggle):

PAGHIPER_API_KEY=your-api-key
PAGHIPER_TOKEN=your-token
PAGHIPER_SANDBOX=true

Clear config after changing env values:

php artisan config:clear

Where to look first

  1. config/paghiper.php — endpoints, credentials, sandbox flag, and any default request options.
  2. The package facade (DevAjMeireles\PagHiper\Facades\PagHiper) — this is the entry point for boleto() and pix() resources.
  3. The README examples for the exact payload keys each resource expects. PagHiper’s API is field-heavy, so verify field names against the README rather than guessing.

First use case: charge a customer with PIX

The most common day-one flow is generating a PIX charge for an existing Order and persisting the returned transaction identifier and QR code:

use DevAjMeireles\PagHiper\Facades\PagHiper;

$charge = PagHiper::pix()->create([
    'order_id'       => $order->id,
    'payer_name'     => $order->customer->name,
    'payer_email'    => $order->customer->email,
    'payer_cpf_cnpj' => $order->customer->document,
    'payer_phone'    => $order->customer->phone,
    'description'    => "Pedido #{$order->id}",
    'amount'         => $order->total,
    'due_date'       => now()->addDay()->toDateString(),
]);

$order->update([
    'gateway'          => 'paghiper',
    'transaction_id'   => $charge['transaction_id'] ?? null,
    'payment_status'   => $charge['status'] ?? 'pending',
    'payment_payload'  => $charge, // keep raw response for support/debug
]);

Swap in PagHiper::boleto() for a boleto flow; the payload shape is similar but with boleto-specific fields (due date, days to expire, late-payment rules).

Sandbox first

Turn PAGHIPER_SANDBOX=true on and validate the full lifecycle (create → poll status → webhook → cancel) before touching production keys. PagHiper sandbox credentials are separate from production.


Implementation Patterns

Wrap the facade in an application service

Don’t scatter PagHiper::… calls across controllers. Introduce a thin PagHiperService or CreatePixCharge action:

final class CreatePixCharge
{
    public function __invoke(Order $order): array
    {
        return PagHiper::pix()->create([
            'order_id'       => (string) $order->id,
            'payer_name'     => $order->customer->name,
            // ...
        ]);
    }
}

This gives you one place to normalize payloads, log responses, and swap gateways later.

Persist everything the gateway sends back

Store at minimum: transaction_id, status, barcode/digitable_line (boleto) or qrcode_image_url/emv (PIX), plus the raw response JSON. PagHiper support requests will ask for the transaction ID, and you will want the raw payload when a customer claims they paid but your app disagrees.

A dedicated payments table keyed by transaction_id (unique index) beats stuffing everything on orders.

Idempotency via order_id

PagHiper uses your order_id as the merchant reference. Make it deterministic (order->id, or a UUID for one-off charges) so that retried jobs or double-submitted forms don’t create duplicate charges. Guard the charge creation with a unique constraint or a lockForUpdate() inside a transaction.

Webhook controller pattern

PagHiper posts status notifications. Keep it dumb and idempotent:

Route::post('/webhooks/paghiper', PagHiperWebhookController::class)
    ->withoutMiddleware(['csrf']);
public function __invoke(Request $request)
{
    $payload = $request->all();

    $payment = Payment::where('transaction_id', $payload['transaction_id'] ?? null)->first();

    if (! $payment) {
        return response()->noContent(); // 204 — unknown transaction
    }

    // Only move forward, never regress statuses
    $payment->update([
        'status'   => $payload['status'] ?? $payment->status,
        'raw'      => $payload,
        'paid_at'  => ($payload['status'] ?? null) === 'paid' ? now() : $payment->paid_at,
    ]);

    event(new PaymentUpdated($payment));

    return response()->noContent();
}

Wrap the handler in a DB transaction, and make it safe to receive the same notification twice.

Polling as a fallback

Webhooks are the primary source of truth, but a scheduled command that re-checks open charges (PagHiper::boleto()->status($id)) catches missed notifications:

Payment::where('status', 'pending')
    ->where('created_at', '<', now()->subMinutes(30))
    ->each(fn ($p) => app(SyncPaymentStatus::class)($p));

Queue the charge creation

PagHiper’s API is external; create the charge from a queued job (CreatePagHiperCharge::dispatch($order)) so checkout stays fast and failures can retry with exponential backoff. Ensure the job is idempotent using the order_id guard above.

Testing

If the package uses the Laravel HTTP client under the hood, Http::fake() in feature tests lets you assert the outgoing payload and simulate responses without hitting PagHiper. For end-to-end confidence, run a small sandbox suite nightly rather than in CI on every commit.

Rendering to the customer

The facade returns an array-like response; expose only what the customer needs. For PIX, show the EMV string and QR image URL with a countdown to due_date. For boleto, render the digitable line and a link to the PDF — don’t force the user to download a PDF to copy the barcode.


Gotchas and Tips

Amount formatting is the classic trap. PagHiper expects money in a specific unit and type (check whether the package wants a string with two decimals or cents). Send 10.5 vs 1050 incorrectly and you’ll charge 100× or 0.01× the intended amount. Write one Money::toPagHiper() helper and use it everywhere.

Sandbox and production credentials are not interchangeable. A common symptom is “401 unauthorized” or “invalid token” that turns out to be production credentials with sandbox=true (or vice versa). Add an assert helper in your service that throws early with a clear message.

config:cache will silently keep old credentials. After changing .env, run php artisan config:clear (or redeploy with cache rebuild). This trips up almost everyone the first time they rotate keys.

Payer document requirements. PagHiper validates CPF/CNPJ. Validate and normalize (strip punctuation) before calling the API — client-side validation alone is not enough. Invalid documents often surface as generic API errors rather than helpful field errors.

Due dates and timezone. Server timezone vs PagHiper’s expectations (usually America/Sao_Paulo) can shift a boleto’s due date by a day. Pass dates as Y-m-d strings built with now('America/Sao_Paulo'), not raw Carbon objects, unless the package explicitly handles them.

Webhook authenticity. The package may or may not verify the webhook payload. Don’t assume it does — compare the transaction_id/order_id against your database and ignore unknown IDs. Never trust the amount from a webhook; trust your own stored order total.

Status transitions are not linear. PagHiper can send pending, paid, canceled, refunded, and possibly processing. Model this as an enum and only allow forward transitions; a delayed pending webhook arriving after paid must not regress the payment.

Response shape varies by resource. Boleto and PIX return different keys (barcode vs QR code). Don’t build a single generic mapper — keep two thin presenters so blade/API responses stay honest about what exists.

Error handling should distinguish transport from business errors. A 500 from PagHiper (retryable) is different from “payer_cpf_cnpj invalid” (not retryable, needs user input). Inspect the response body and map to domain exceptions (PagHiperTransientException vs PagHiperValidationException) so your queue can decide whether to retry.

Rate limits and retries. If you fan out charges in a job batch, add a small delay and cap concurrency. Use retry(3, fn ($attempt) => $attempt * 1000) on the job rather than tight loops.

This package is small and young (21 stars, 0 dependents). That’s fine for a focused integration, but don’t assume it covers refunds, splits, or advanced features. Read the source of the resource classes — they’re small enough to audit in an afternoon — and wrap the facade in your own service so an eventual fork or swap is a one-file change. Pin the version in composer.json and review changelogs on upgrade; the last release date can drift.

Extension point to consider: if the package exposes custom HTTP client or event hooks, use them for logging and metrics (request latency, failure rate) rather than sprinkling Log::info inside controllers. A single middleware or event listener gives you observability across boleto and PIX with no duplication.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package