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

Payment Contracts Laravel Package

tourze/payment-contracts

tourze/payment-contracts provides shared PHP interfaces and contracts for building payment integrations within the Tourze ecosystem, giving developers a consistent foundation for gateways, transactions, and payment flows across projects.

View on GitHub
Deep Wiki
Context7

Getting Started

tourze/payment-contracts is an interface/contract package: it ships abstractions, not a working payment gateway. The 1.0.0 tag is the first stable release, which mainly signals that the contract surface is intended to be frozen — treat it as "the interfaces you code against," not "a payment library you call."

Minimal steps:

  1. composer require tourze/payment-contracts (it should be a normal require dependency, not require-dev, since your implementations will type-hint against it).
  2. Read the source before anything else. With a changelog this thin, vendor/tourze/payment-contracts/src/ is the documentation. Use composer show -a tourze/payment-contracts and then open every interface file — the whole package is usually a handful of small interfaces.
  3. Identify the entry-point contract (typically something like a payment/charge interface plus a request/response value object pair) and the factory or resolver contract used to obtain a gateway instance.
  4. First use case: write a thin adapter that implements the contract on top of a real provider SDK (Stripe, WeChat Pay, Alipay, etc.), then bind it in a service provider behind the interface.
// app/Payments/StripeGateway.php
final class StripeGateway implements \Tourze\PaymentContracts\PaymentInterface
{
    public function __construct(private \Stripe\Client $client) {}
    // implement each method defined by the interface
}
// app/Providers/PaymentServiceProvider.php
public function register(): void
{
    $this->app->bind(
        \Tourze\PaymentContracts\PaymentInterface::class,
        \App\Payments\StripeGateway::class,
    );
}

Resolve via the container (app(PaymentInterface::class) or constructor injection) rather than instantiating gateways directly — that is the entire point of depending on a contracts package.

Implementation Patterns

Adapter-per-provider, resolve-by-interface. Bind one implementation per provider and select between them with a context-aware binding or a small gateway registry keyed by a payment_method / channel string. Keep the registry in your own code; contracts packages generally do not ship a manager.

Wrap the provider SDK, do not leak it. The contract exists so controllers, jobs, and listeners never import Stripe/Alipay classes. Confine SDK exceptions to your adapter and translate them into the package's own exception types (if it defines any) or into domain exceptions of your own. This is what makes swapping providers cheap later.

Value objects at the boundary. Contracts packages usually define request/response DTOs. Build them in a form request or a small application service, not inside a controller closure. If the DTOs are immutable, use named constructors or fromArray() helpers in your own layer rather than scattering new calls.

Test doubles are the main day-to-day win. Because you depend on an interface, every consumer becomes trivially testable:

$this->mock(PaymentInterface::class, function ($mock) {
    $mock->shouldReceive('charge')->once()->andReturn(/* response DTO */);
});

Write one "contract test" (a shared abstract test case) that every adapter must pass — success, decline, timeout, refund, idempotent retry. That is the single highest-value artefact when working with a contracts-only dependency.

Integration tips. Pair the contracts with a concrete driver package if one exists in the same organisation's ecosystem, otherwise expect to own all adapters. Hook the contract into Laravel's payment lifecycle at the service layer, not in models; fire domain events (PaymentSucceeded, PaymentFailed) from your adapter's callers so the interface stays free of framework concerns.

Gotchas and Tips

  • Contracts-only means zero runtime behaviour. If you installed this expecting a payable gateway, you will get "interface not instantiable" from the container until you bind an implementation. That binding is mandatory, and a missing one in a queued job surfaces as a confusing BindingResolutionException deep in a worker.
  • Verify the interfaces against the source, not the changelog. Release notes for 1.0.0 are a bare changelog link. Diff the interface files between tags (composer show -a, or fetch the tag) before upgrading past 1.0.x; interface packages break consumers silently at the type level rather than at runtime.
  • 1.0.0 is a stability promise, not a feature announcement. Nothing indicates deprecations or breaking changes relative to prior tags — there is effectively no prior assessment to compare against. Pin with ^1.0 and let the constraints do the work.
  • Namespace and autoload assumptions. Tourze packages are numerous and small; confirm the actual namespace (Tourze\... vs a PSR-4 quirk) and whether the package declares illuminate/support or stays framework-agnostic. Framework-agnostic contracts need manual service-provider wiring and are not auto-discovered — check for a extra.laravel.providers block in composer.json.
  • Watch for DTO drift from provider payloads. Contract DTOs are deliberately generic; provider responses are not. Keep the raw provider payload stashed (a raw property or a log entry) so you can debug reconciliation without re-querying the provider.
  • Idempotency and money are your responsibility. Contracts describe shape, not semantics. Store amounts in integer minor units, always pass an idempotency key through your adapter, and never let a nullable status field default to "success" in a match.
  • Extension point: if the contract set is missing something (partial refunds, multi-currency, webhook verification), add a new interface in your own namespace and have your adapters implement both, rather than forking the package — forks of contracts packages fragment the type system across your app.
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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource