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

Easypay Php Laravel Package

gordalina/easypay-php

PHP library for integrating Easypay payments into your application, with helpers for creating payment references, handling callbacks, and working with Easypay’s API in a simple, framework-agnostic way.

View on GitHub
Deep Wiki
Context7

Getting Started

  • composer require gordalina/easypay-php — there is no Laravel service provider and no package discovery. Nothing registers itself; the wiring is entirely on you.
  • Read in this order: the README (thin, mostly examples), src/Easypay.php (the public method surface — this is what you actually call), src/Config.php (credentials and base URL), then src/Request/ (one class per operation: reference, card, direct debit, status).
  • Credentials come from the easypay backoffice: cin (client identification number), user, password, and the account's base_url. Production is typically https://www.easypay.pt/_s/; confirm test endpoints with your account manager before assuming they exist.

Minimal wiring:

// config/services.php
'easypay' => [
    'cin'      => env('EASYPAY_CIN'),
    'user'     => env('EASYPAY_USER'),
    'password' => env('EASYPAY_PASSWORD'),
    'base_url' => env('EASYPAY_BASE_URL', 'https://www.easypay.pt/_s/'),
],
// AppServiceProvider::register()
$this->app->singleton(\Easypay\Config::class, fn () => new \Easypay\Config(config('services.easypay')));

$this->app->singleton(\Easypay\Easypay::class, fn ($app) => new \Easypay\Easypay($app->make(\Easypay\Config::class)));

Your first use case should be the checkout → Multibanco reference flow: create a payment, render entity/reference/amount to the customer, store the raw response, then poll or receive a notification to mark the order paid. It exercises config, request building, response parsing, and status lookup in one path, which is a good smoke test before touching card or direct debit.

Implementation Patterns

  • Wrap it, don't inject it. Never type-hint Easypay\Easypay in a controller. Build App\Services\Payments\EasypayGateway with your own method signatures (createReference(Order $order): Reference, status(string $id): PaymentStatus) returning your own DTOs. The library's return types are loose array/object shapes; the wrapper is what gives you a stable seam if you ever move to easypay v3 or another PSP.
  • Inject the HTTP client through the wrapper. The library sits on Guzzle; allowing the client to be swapped lets you use MockHandler in feature tests without hitting the network.
  • Mirror the library's own convention — one class per operation. CreateMultibancoReference, CreateCardPayment, CreateDirectDebit, each with handle() that builds the payload from an order. Keeps your domain out of the transport layer.
  • Persist the raw request/response pair. A payments table with order_id, method, reference, entity, amount, status, raw_request, raw_response. When easypay support asks what happened, this is the only thing that answers the question.
  • Drive state with events, not with the gateway. Dispatch PaymentInitiated, PaymentConfirmed, PaymentExpired; listeners update the order and send mail. The gateway should never queue mail or touch invoices.
  • Poll as a backstop. A scheduled command (everyFiveMinutes) that calls getPaymentStatus on open references and transitions them. Callbacks are best-effort; the schedule is what actually reconciles.
  • Queue the outbound call. easypay's legacy endpoints are slow under load. A dispatch() behind a Redis queue keeps checkout responsive and gives you retry semantics you control.
  • Notification route outside the web middleware group — no CSRF, no session. Match the payload's reference and amount against your stored row, then transition idempotently.
  • Testing. Freeze time, use Guzzle MockHandler for the HTTP layer, and assert the events fired. Add a "test credentials" block under services.easypay and switch on app()->environment() so no feature test ever reaches production.

Gotchas and Tips

  • The package is effectively unmaintained. 16 stars, zero dependents, and it targets easypay's legacy _s/ API. easypay has been pushing their v3/Checkout API for years. Confirm your CIN still works against the legacy endpoints, and make the wrapper your only entry point so the eventual swap is one class.
  • No service provider, no facade, no publishable config. Everything in Getting Started is yours to write. There's nothing in vendor/ to lean on for idiomatic Laravel wiring.
  • Amounts are decimal strings. "10.00" — not integer cents, not a float, not 10. Format with number_format($cents / 100, 2, '.', '') and fail loudly on more than two decimals.
  • The base_url trailing slash matters. The library concatenates paths onto it; missing or doubled slashes produce 404s that surface looking like authentication errors.
  • A CIN mismatch returns generic errors. Almost every "invalid request" during onboarding is a CIN that doesn't match the credentials, or test credentials pointed at production. Log the raw response body before surfacing anything to the user.
  • Never infer success from HTTP 200. The API returns URL-encoded or XML-ish bodies with a status field and an error message. Check status !== 'ok' explicitly and read the message.
  • Idempotency is on you. Send a stable o_id / order reference on every create call. Timeouts and queue redeliveries can produce two references for one order otherwise; dedupe on your side before retrying.
  • Set explicit timeouts. Something like 10s connect / 20s read. And never retry a non-idempotent create without first checking whether the reference already exists.
  • Notifications are application/x-www-form-urlencoded, not JSON. Use $request->post(); don't validate against a JSON shape.
  • Reference expiry is your problem. Multibanco references expire in a few days; expire them locally in a scheduled command so the UI never shows a dead reference as payable.
  • Card, Multibanco, and direct debit have different state machines — authorization vs. capture, mandate vs. one-shot. Don't collapse to a single paid boolean; store easypay's own status string.
  • The library has no logging hooks. Wrap each call with Log::withContext(['easypay' => $payload]); you will want the correlation details when reconciling.
  • For card payments, never pass the PAN through your server. Redirect or iframe to easypay's hosted page — this keeps the PCI scope off your infrastructure and is the intended flow anyway.
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.
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
kda/filament-dynamic-navigation
bypersoft/signbox