Skip to content

3.1.1 - Smarter retries, typed webhooks, and eight new helpers

Latest

Choose a tag to compare

@bashgeek bashgeek released this 18 Apr 05:25
522834a

Eight new features landed since 3.1.0, all fully backward-compatible. No removed methods, no signature changes, nothing to migrate.

429 handling with Retry-After (#674)

The retry middleware now handles 429 Too Many Requests. When PayPal sends a Retry-After header the delay respects it exactly; without it, the existing exponential backoff kicks in (500ms, 1s, 2s, up to 8s). Nothing to configure.

WebhookEvent value object (#676)

Typed readonly wrapper around PayPal webhook payloads:

use Srmklive\PayPal\Events\WebhookEvent;

$event = WebhookEvent::fromRawBody($request->getContent());

if ($event->is('PAYMENT.CAPTURE.COMPLETED')) {
    $captureId = $event->resource['id'];
}

Fields: id, eventType, resourceType, summary, createTime, resource, rawPayload.

Transaction reporting helpers (#678)

Four wrappers on top of listTransactions() for the common cases:

// Single transaction by ID, looks back up to 31 days
$tx = $provider->getTransactionDetails('5TY05013RG002845M');

// Date range shorthand, no manual ISO 8601 formatting needed
$txns = $provider->listTransactionsForDateRange('2025-01-01', '2025-01-31');

// Filter by PayPal transaction type code
$txns = $provider->listTransactionsByType('T0006', '2025-01-01', '2025-01-31');

// Filter by status (S = success, P = pending, etc.)
$txns = $provider->listTransactionsByStatus('S', '2025-01-01', '2025-01-31');

Subscription lifecycle helpers (#675)

// Alias for activateSubscription() with a sensible default reason
$provider->reactivateSubscription($subscriptionId);

// True only when status === 'ACTIVE'
if ($provider->isSubscriptionActive($subscriptionId)) { ... }

MockPayPalClient (#672)

A public MockPayPalClient lives at Srmklive\PayPal\Testing\MockPayPalClient. Queue responses in tests without touching the sandbox:

use Srmklive\PayPal\Testing\MockPayPalClient;

$client = new MockPayPalClient($credentials);
$client->addResponse(201, ['id' => 'ORDER-123', 'status' => 'CREATED']);

$order = $client->createOrder([...]);
// $client->requests() to inspect what was sent

BillingPlanBuilder (#673)

Fluent builder for billing plan payloads. Covers all cycle types, trial pricing, and payment preferences:

use Srmklive\PayPal\Services\BillingPlanBuilder;

$plan = BillingPlanBuilder::make('Pro Plan', 'PROD-ABC123')
    ->trialCycle(days: 14, price: 0)
    ->monthlyPrice(29.99)
    ->build();

$response = $provider->createBillingPlan($plan);

setPartnerAttributionId() (#677)

Set the PayPal-Partner-Attribution-Id BN code once after initialisation and it sticks for all subsequent requests from that instance:

$provider->setPartnerAttributionId('YourBNCode_Cart');

Pay Upon Invoice / BNPL for DE/AT (#679)

setPaymentSourcePayUponInvoice() joins the existing payment source setters. Available for merchants in Germany and Austria:

$provider->setPaymentSourcePayUponInvoice([
    'name'            => ['given_name' => 'John', 'surname' => 'Doe'],
    'email'           => 'john.doe@example.com',
    'birth_date'      => '1990-01-01',
    'phone'           => ['country_code' => '49', 'national_number' => '1234567890'],
    'billing_address' => [
        'address_line_1' => 'Hauptstraße 1',
        'admin_area_2'   => 'Berlin',
        'postal_code'    => '10115',
        'country_code'   => 'DE',
    ],
    'experience_context' => [
        'locale'     => 'de-DE',
        'return_url' => 'https://example.com/paypal-success',
        'cancel_url' => 'https://example.com/paypal-cancel',
    ],
]);

$order = $provider->createOrderWithPaymentSource([
    'intent'         => 'CAPTURE',
    'purchase_units' => [['amount' => ['currency_code' => 'EUR', 'value' => '99.00']]],
]);

Upgrading

composer update srmklive/paypal

No code changes required.