# Plug&Pay PHP SDK ## Introduction The Plug&Pay PHP SDK is a comprehensive library designed to simplify communication with the Plug&Pay API, a payment and affiliate marketing platform. This SDK provides a type-safe, object-oriented interface for PHP developers to integrate payment processing, order management, product catalog, subscription handling, and checkout functionality into their applications. Built with modern PHP 8.1+ features, the SDK leverages Guzzle HTTP client for reliable API communication and implements OAuth 2.0 authorization flow for secure authentication. The SDK follows a consistent service-oriented architecture where each resource (products, orders, checkouts, subscriptions, etc.) is managed through dedicated service classes. It provides fluent interfaces for building queries, comprehensive error handling with custom exceptions, and support for eager loading of related resources. The SDK includes entity models with immutable getters and fluent setters, filter classes for advanced querying, and built-in support for pagination and sorting. With 99% code coverage and extensive test suite, it offers production-ready reliability for e-commerce applications integrating with Plug&Pay's payment and marketing infrastructure. ## API Documentation and Code Examples ### Client Initialization Initialize the SDK client with access token and optional configuration. ```php generateAuthorizationUrl( clientId: $clientId, state: $state, codeVerifier: $codeVerifier, redirectUrl: $redirectUrl ); // Redirect user to $authUrl for authorization header("Location: $authUrl"); ``` ### OAuth Token Management Exchange authorization code for access tokens and manage token lifecycle. ```php getCredentials( code: $_GET['code'], codeVerifier: $storedCodeVerifier, redirectUrl: 'https://yourapp.com/callback', clientId: 12345, tenantId: 67890 ); $accessToken = $response->body()['access_token']; $refreshToken = $response->body()['refresh_token']; $expiresIn = $response->body()['expires_in']; // Store tokens securely $_SESSION['access_token'] = $accessToken; $_SESSION['refresh_token'] = $refreshToken; } catch (ValidationException $e) { echo "Validation error: " . $e->getMessage(); } catch (NotFoundException $e) { echo "Resource not found: " . $e->getMessage(); } // Refresh tokens when needed $client = new Client($accessToken); $response = $client->refreshTokensIfNeeded( refreshToken: $refreshToken, clientId: 12345, tenantId: 67890 ); if ($response->body()['refreshed']) { $newAccessToken = $response->body()['access_token']; $newRefreshToken = $response->body()['refresh_token']; // Update stored tokens } // Revoke tokens (logout) $client->revokeTokens(); ``` ### Product Management Create, read, update, and delete products with pricing and inventory management. ```php setTitle('Premium Course') ->setPublicTitle('Learn Web Development') ->setDescription('Complete web development course with 50+ hours of content') ->setType(ContractType::STANDARD) ->setPhysical(false) ->setSku('COURSE-001') ->setLedger(8000); // Accounting ledger code try { $createdProduct = $productService ->include(ProductIncludes::PRICING) ->create($product); echo "Product created with ID: " . $createdProduct->id(); } catch (\Exception $e) { echo "Error creating product: " . $e->getMessage(); } // Retrieve a single product by ID $product = $productService ->include(ProductIncludes::PRICING, ProductIncludes::STOCK) ->find(123); echo $product->title(); echo $product->description(); // List products with filtering $filter = new ProductFilter(); $filter->query('course') // Search query ->type(ContractType::STANDARD) ->limit(50) ->page(1) ->sort(ProductSortType::TITLE) ->direction(Direction::ASC) ->tag(['digital', 'education']) ->hasLimitedStock(false) ->isDeleted(false); $products = $productService ->include(ProductIncludes::PRICING) ->get($filter); foreach ($products as $product) { echo $product->id() . ": " . $product->title() . "\n"; } // Update a product $updatedProduct = $productService->update(123, function($product) { $product->setTitle('Updated Premium Course') ->setDescription('New description with updated content'); }); // Delete a product $productService->delete(123); ``` ### Order Management Handle customer orders with billing, items, and payment processing. ```php setEmail('customer@example.com') ->setFirstname('John') ->setLastname('Doe') ->setPhone('+31612345678'); $address = new Address(); $address->setCountry(CountryCode::NL) ->setStreet('Keizersgracht') ->setHouseNumber('123') ->setCity('Amsterdam') ->setZipcode('1015 CS'); $billing = new OrderBilling(); $billing->setContact($contact) ->setAddress($address); $item = new Item(); $item->setLabel('Premium Course') ->setProductId(456) ->setQuantity(1) ->setAmount(9900); // Amount in cents $comment = new Comment(); $comment->setValue('Customer requested express delivery'); $order = new Order(); $order->setBilling($billing) ->setItems([$item]) ->setComments([$comment]); try { $createdOrder = $orderService ->include(OrderIncludes::BILLING, OrderIncludes::ITEMS) ->create($order); echo "Order created with ID: " . $createdOrder->id(); echo "Order total: " . $createdOrder->total() / 100 . " EUR"; } catch (\Exception $e) { echo "Error creating order: " . $e->getMessage(); } // Retrieve an order $order = $orderService ->include(OrderIncludes::BILLING, OrderIncludes::PAYMENT, OrderIncludes::ITEMS) ->find(789); echo "Order status: " . $order->status()->value; echo "Customer email: " . $order->billing()->contact()->email(); // List orders with filtering $filter = new OrderFilter(); $filter->limit(100) ->page(1); $orders = $orderService ->include(OrderIncludes::BILLING) ->get($filter); foreach ($orders as $order) { echo "Order #" . $order->id() . " - " . $order->billing()->contact()->email() . "\n"; } // Update an order $updatedOrder = $orderService->update(789, function($order) { $comment = new Comment(); $comment->setValue('Payment received, processing shipment'); $order->setComments([$comment]); }); // Delete an order $orderService->delete(789); ``` ### Checkout Management Create and manage checkout pages for products. ```php setId(456); // Product ID $checkout = new Checkout(); $checkout->setName('Premium Course Checkout') ->setSlug('premium-course') ->setUrl('https://yourstore.com/checkout/premium-course') ->setReturnUrl('https://yourstore.com/success') ->setPreviewUrl('https://yourstore.com/preview/premium-course') ->setPrimaryColor('#007bff') ->setSecondaryColor('#6c757d') ->setIsActive(true) ->setIsExpired(false) ->setProduct($checkoutProduct); try { $createdCheckout = $checkoutService ->include(CheckoutIncludes::PRODUCT) ->create($checkout); echo "Checkout created with ID: " . $createdCheckout->id(); echo "Checkout URL: " . $createdCheckout->url(); } catch (\Exception $e) { echo "Error creating checkout: " . $e->getMessage(); } // Retrieve a checkout $checkout = $checkoutService ->include(CheckoutIncludes::PRODUCT) ->find(123); echo "Checkout name: " . $checkout->name(); echo "Is active: " . ($checkout->isActive() ? 'Yes' : 'No'); // List checkouts with pagination $filter = new CheckoutFilter(); $filter->limit(20)->page(1); $checkouts = $checkoutService ->include(CheckoutIncludes::PRODUCT) ->get($filter); foreach ($checkouts as $checkout) { echo $checkout->name() . " - " . $checkout->url() . "\n"; } // Get checkouts as collection with metadata $checkoutCollection = $checkoutService->getCollection($filter); foreach ($checkoutCollection->checkouts() as $checkout) { echo $checkout->name() . "\n"; } echo "Total: " . $checkoutCollection->meta()['total']; echo "Current page: " . $checkoutCollection->meta()['current_page']; // Update a checkout $updatedCheckout = $checkoutService->update(123, function($checkout) { $checkout->setName('Updated Checkout Name') ->setIsActive(false); }); // Delete a checkout $checkoutService->delete(123); ``` ### Subscription Management Manage recurring subscriptions for customers. ```php setProductId(456) ->setContactId(789) ->setQuantity(1) ->setIsActive(true); try { $createdSubscription = $subscriptionService ->include(SubscriptionIncludes::PRODUCT, SubscriptionIncludes::CONTACT) ->create($subscription); echo "Subscription created with ID: " . $createdSubscription->id(); echo "Next billing date: " . $createdSubscription->nextBillingAt()->format('Y-m-d'); } catch (\Exception $e) { echo "Error creating subscription: " . $e->getMessage(); } // Retrieve a subscription $subscription = $subscriptionService ->include(SubscriptionIncludes::PRODUCT, SubscriptionIncludes::ORDER) ->find(123); echo "Subscription status: " . ($subscription->isActive() ? 'Active' : 'Inactive'); echo "Product: " . $subscription->product()->title(); // List all subscriptions $filter = new SubscriptionFilter(); $subscriptions = $subscriptionService ->include(SubscriptionIncludes::PRODUCT) ->get($filter); foreach ($subscriptions as $subscription) { echo "Subscription #" . $subscription->id() . " - " . $subscription->product()->title() . "\n"; } // Update a subscription $updatedSubscription = $subscriptionService->update(123, function($subscription) { $subscription->setQuantity(2) ->setIsActive(false); }); // Cancel a subscription $subscriptionService->delete(123); ``` ### Error Handling Handle API errors with custom exceptions. ```php find(999); echo $product->title(); } catch (NotFoundException $e) { // Handle 404 errors echo "Product not found: " . $e->getMessage(); } catch (ValidationException $e) { // Handle validation errors (422) echo "Validation failed: " . $e->getMessage(); // Access individual validation errors foreach ($e->errors() as $error) { echo "Field: " . $error->field() . "\n"; echo "Message: " . $error->message() . "\n"; } } catch (DecodeResponseException $e) { // Handle JSON decode errors echo "Failed to decode response: " . $e->getMessage(); } catch (RelationNotLoadedException $e) { // Handle accessing relations that weren't included echo "Relation not loaded: " . $e->getMessage(); echo "Use ->include() to load required relations"; } catch (\GuzzleHttp\Exception\GuzzleException $e) { // Handle network errors echo "Network error: " . $e->getMessage(); } catch (\Exception $e) { // Catch-all for other errors echo "An error occurred: " . $e->getMessage(); } ``` ### Additional Services Access other platform features through specialized service classes. ```php get(); foreach ($taxRates as $taxRate) { echo $taxRate->country() . ": " . $taxRate->rate() . "%\n"; } // Affiliate seller management $affiliateService = new AffiliateSellerService($client); $affiliateSeller = $affiliateService->find(123); echo "Affiliate: " . $affiliateSeller->name(); $affiliateSellers = $affiliateService->get(); // Membership settings $membershipsService = new MembershipsSettingService($client); $membershipSetting = $membershipsService->find(456); $membershipsService->update(456, function($setting) { $setting->setTitle('VIP Membership'); }); // Tenant information $tenantService = new TenantService($client); $tenant = $tenantService->show(); echo "Tenant name: " . $tenant->name(); // Portal settings $portalService = new PortalSettingService($client); $settings = $portalService->show(); $portalService->update(function($settings) { $settings->setCompanyName('My Company'); }); // Order payment management $paymentService = new OrderPaymentService($client); $payment = $paymentService->find(789); $paymentService->update(789, function($payment) { $payment->setStatus(PaymentStatus::PAID); }); // Business rules $ruleService = new RuleService($client); $rules = $ruleService->get(); $rule = $ruleService->find(123); ``` ## Summary and Integration The Plug&Pay PHP SDK serves as a comprehensive solution for e-commerce applications requiring payment processing, subscription management, and digital product delivery. Primary use cases include building custom storefronts with product catalogs, implementing recurring billing systems for SaaS applications, creating checkout flows for digital downloads, managing customer orders with complex billing requirements, and integrating affiliate marketing functionality. The SDK is particularly suited for applications that need granular control over the payment flow while maintaining clean separation between business logic and API communication. Integration follows a straightforward pattern: initialize the Client with OAuth credentials, instantiate required service classes, use entity objects to represent data structures, and leverage filter classes for complex queries. The SDK's fluent interface allows for readable, chainable method calls, while built-in exception handling ensures robust error management. Related resources can be eagerly loaded using the include() method to minimize API calls, and all responses are automatically mapped to strongly-typed entity objects. The SDK requires PHP 8.1+ and Guzzle HTTP client, installs via Composer, and follows PSR-4 autoloading standards for seamless integration into modern PHP applications.