Sell worldwide, today, with Vatly. Dedicated to EU based SAAS merchants and software companies, accept creditcard, PayPal, ApplePay, iDEAL and more.
This is the raw API client. If you're building a Laravel application, you almost certainly want vatly/vatly-laravel instead — it provides a Cashier-style Billable trait, Eloquent models, a wired webhook endpoint, and event-bus integration on top of this SDK.
Other framework drivers (Symfony, WordPress) are on the roadmap. To build one, see the Driver Author Guide in vatly/vatly-fluent-php.
You can install the package via composer:
composer require vatly/vatly-api-phpuse Vatly\API\VatlyApiClient;
$vatly = new VatlyApiClient();
$vatly->setApiKey('test_your_api_key_here');
$vatly->checkouts->create([...]);For detailed documentation, see docs/README.md.
The SDK automatically sends an Idempotency-Key header on every POST and PATCH request.
$checkout = $vatly->checkouts->create([
'products' => [
['id' => 'plan_abc123', 'quantity' => 1],
],
'redirectUrlSuccess' => 'https://yourapp.com/success',
'redirectUrlCanceled' => 'https://yourapp.com/canceled',
]);To set a custom key for the next mutating request, use setIdempotencyKey(). The manual key is cleared after the request is sent.
$vatly->setIdempotencyKey('checkout-create-123');
$checkout = $vatly->checkouts->create([
'products' => [
['id' => 'plan_abc123', 'quantity' => 1],
],
'redirectUrlSuccess' => 'https://yourapp.com/success',
'redirectUrlCanceled' => 'https://yourapp.com/canceled',
]);Some endpoint methods also accept a per-request idempotencyKey option:
$checkout = $vatly->checkouts->create([...], [
'idempotencyKey' => 'checkout-create-123',
]);
$subscription = $vatly->subscriptions->update('subscription_123', [
'quantity' => 2,
], [
'idempotencyKey' => 'subscription-update-123',
]);You can replace or disable the automatic generator when needed:
$vatly->setIdempotencyKeyGenerator(new MyIdempotencyKeyGenerator());
$vatly->clearIdempotencyKeyGenerator();Verify and parse incoming Vatly webhooks with Webhook::parse(), which returns a typed WebhookPayload:
use Vatly\API\Webhooks\Webhook;
$event = Webhook::parse($rawBody, $signatureHeader, $webhookSecret);For strongly-typed, per-event objects, this package also owns immutable event DTOs under Vatly\API\Webhooks\Events\* (e.g. OrderPaid, RefundCompleted, SubscriptionStarted). Money fields are Vatly\API\Types\Money (decimal-string + currency; call $event->total->toCents() / read $event->total->currency to flatten at your persistence edge) and the VAT breakdown is Vatly\API\Types\TaxSummaryCollection; order lines are Vatly\API\Types\OrderLineData. These are the canonical event shapes that higher-level integrations build on.
Vatly\API\Webhooks\WebhookEventFactory turns a verified payload into one of these typed events — verify, parse, and map all happen in api-php now. Pass it a VatlyApiClient and hand it the WebhookReceived from fromPayload():
use Vatly\API\Webhooks\Webhook;
use Vatly\API\Webhooks\WebhookEventFactory;
$payload = Webhook::parse($rawBody, $signatureHeader, $webhookSecret);
$factory = new WebhookEventFactory($client);
$event = $factory->createFromWebhook($factory->fromPayload($payload));
// e.g. $event instanceof Vatly\API\Webhooks\Events\OrderPaidBecause Vatly sends fat, HMAC-signed payloads — the delivery's object is byte-identical to the corresponding GET /…/{id} body — the factory builds every event straight from the signed payload (hydrating the matching api-php resource in memory for money/tax-bearing events). It makes no follow-up API call. Use getSupportedEvents() / isSupported() to inspect the event surface.
The incoming webhook payloads are described in the webhooks: section of openapi.yaml. See docs/Webhooks.md for the full guide.
composer testPlease see CHANGELOG for more information on what has changed recently.
Send in a Pull Request if you'd like to contribute to this package.
In case of a security vulnerability, please shoot us an email at security@vatly.com.
The MIT License (MIT). Please see License File for more information.