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

Payture Inpay Bundle Laravel Package

lamoda/payture-inpay-bundle

Symfony bundle for integrating the Payture InPay payment API, with bundle configuration and service wiring that make Payture payment operations easier to use in Symfony-based PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is a thin Laravel wrapper around payture-inpay-php-client, exposing the Payture InPay merchant API (session initialisation, 3-D Secure completion, state queries, refunds, and card registration/charging) through config-driven bindings and, usually, a facade.

Minimal path to first payment:

  1. composer require <vendor>/laravel-payture-inpay (v1.2 now pulls payture-inpay-php-client v1.2).
  2. Publish config: php artisan vendor:publish --tag=payture-config.
  3. Set credentials in .env — merchant KEY, PASSWORD, and the API host. Keep sandbox and production hosts in separate env blocks; never share keys across environments.
  4. Build one happy-path controller: create a session → redirect the user to the returned payment URL → on return, call GetSessionState and persist the result.

Where to look first:

  • The package's config/payture.php for host/terminal/key wiring and any timeout settings.
  • The service provider to see which class names are bound in the container (this is your primary extension seam).
  • vendor/payture/... for the v1.2 client itself — the release notes only say the client was bumped to v1.2, so diff the vendored client against what you previously ran to spot renamed response fields, new methods, or changed signatures before writing code against it.

The first real use case is almost always a one-off redirect payment for an order. Get that working end-to-end in sandbox with the provider's test cards before touching refunds or recurring charges — those require the password credential and are the parts most likely to differ in client v1.2.

Implementation Patterns

Persist before you redirect. Create your own payments row (order id, session id, amount, status, raw response) before sending the user to Payture. The session id is your only handle for everything that follows; losing it means an orphaned payment you can only resolve by reconciliation.

Order ids. Generate a unique, URL-safe, alphanumeric order id per attempt and store it. Do not reuse an order id across retries — the gateway will reject or conflate attempts. Keep a separate human-facing order number if you need one.

Never trust the return URL. The browser lands back with query parameters that are trivially forgeable. Treat the return purely as a trigger to call GetSessionState(sessionId) (or the client v1.2 equivalent) server-side, then transition your payment record based on that response. This is also where you fulfil the order — inside a DB transaction with lockForUpdate() on the payment row so a duplicate browser refresh or a concurrent poll cannot double-fulfil.

Wrap the client, don't scatter it. Bind the client in a small PaytureGateway service that maps the client's response objects into your own value objects (PaymentResult, RefundResult). When the underlying client changes shape — which is precisely what a v1.2 bump risks — you fix one class instead of every controller.

Refunds and partial refunds. These need the merchant password in addition to the key. Amounts are in minor units, so refunding 100.00 RUB means 10000. Queue refunds rather than doing them inline in a request: they are slow, they can fail transiently, and you want a retry budget plus a refunds table recording request/response per attempt. Refund against the original order id, and cap cumulative refunds against the captured amount in your own code — don't rely on the gateway to reject over-refunds gracefully.

3-D Secure. Handle the two-phase flow explicitly: initial call returns a redirect to the ACS, then you submit the MD/PaRes pair back through the client's pay/3DS method. Model this as a distinct state (requires_3ds) rather than a special case inside the success branch. Keep the ACS return URL deterministic per order so a lost session doesn't strand the user.

Recurring / card-on-file. Use the register-then-charge pair; store only the returned card token, never the PAN. Treat the token as sensitive: encrypt at rest and keep it out of logs and serialised API responses.

Reconciliation job. Schedule a command that re-queries GetSessionState for payments stuck in pending/New older than N minutes. Webhooks and browser returns both get lost; polling is the backstop that keeps your ledger honest. Make the job idempotent — it will race with the return-URL handler.

Testing. Point the config at the sandbox host, use the provider's published test cards, and for unit tests bind a fake gateway (or Http::fake() if the client is Guzzle-based) so CI never hits the network. Assert on your own value objects, not on the client's DTOs.

Gotchas and Tips

  • Minor units everywhere. The single most common production bug with this gateway family is sending 199.00 where 19900 is expected, or the reverse on refunds. Enforce integers in a money value object and format only at the presentation layer. Never put a float near this API.
  • Two credentials, different scopes. The key is used for most operations; the password is required for refunds/charges/unblock. A Success=false on refund while payments work fine is almost always a missing password, not a bad key.
  • HTTP 200 does not mean success. The API commonly returns 200 OK with Success=false and an ErrCode. If the client v1.2 doesn't throw, your try/catch is decorative. Check the success flag explicitly in the gateway and map ErrCode values to your own exception types so callers can distinguish "declined" from "malformed request" from "gateway down".
  • The v1.2 client bump is the actual risk in this release. Before deploying: read the vendored client's changelog/diff, check for renamed or relocated response properties, changed method signatures, a bumped minimum PHP version, and any Guzzle constraint shift that could conflict with your app. Commit composer.lock, run the full suite, and exercise one sandbox payment and one sandbox refund manually. A transitive client bump is exactly the class of change that passes CI and fails in production.
  • Don't auto-retry session creation. Init is not idempotent; a retried timeout can create two sessions for one order and confuse reconciliation. Retry only state queries.
  • Set explicit HTTP timeouts. The default may be unbounded, and these calls sit in the user's request path. Use a short connect timeout plus a queue for anything non-interactive.
  • PCI surface. Card data should go to Payture's hosted page or their API directly — never through your own form unless you have accepted the SAQ D burden. Mask PANs in logs, and scrub request/response bodies in exception handlers; the client will happily include sensitive fields in a stack trace.
  • Debugging playbook: enable the package/client HTTP logging in non-production, log the sessionId on every branch, and always reproduce with the sandbox host first. Most "gateway is broken" tickets resolve to a wrong host, a trailing slash in the host URL, or an amount-unit mistake.
  • Extension points: the container binding for the client class, the published config file, and (if present) any events fired around session lifecycle. Prefer overriding the binding with your own subclass over editing vendor code — you will need to take the v1.3 bump cleanly.
  • Multi-terminal / multi-tenant. If you run more than one terminal, resolve config per tenant at call time rather than relying on the singleton-bound client; a cached client with the wrong key is a silent cross-tenant leak.
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.
skyraptor/chatter
edlugz/sasapay
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