### Install Payvia Extension Source: https://github.com/glueful/payvia/blob/main/README.md Install the Payvia composer package, rebuild the extension cache, and run database migrations. ```bash composer require glueful/payvia # Rebuild extension cache php glueful extensions:cache # Run migrations for payments php glueful migrate run ``` -------------------------------- ### Install Payvia Extension with Composer Source: https://context7.com/glueful/payvia/llms.txt Install the Payvia extension using Composer. After installation, rebuild the extension discovery cache and run database migrations to create necessary tables. ```bash composer require glueful/payvia # Rebuild the extension discovery cache php glueful extensions:cache # Apply database migrations (payments, billing_plans, invoices tables) php glueful migrate run ``` -------------------------------- ### Verify Payvia Installation Source: https://github.com/glueful/payvia/blob/main/README.md Check extension discovery and provider wiring using Glueful CLI commands. Run database migrations if they were not auto-run. ```bash php glueful extensions:list php glueful extensions:info Payvia php glueful extensions:why Glueful\Extensions\Payvia\PayviaServiceProvider run database migrations (if not auto‑run): php glueful migrate run ``` -------------------------------- ### Create a Billing Plan via cURL Source: https://github.com/glueful/payvia/blob/main/README.md This cURL example demonstrates how to create a new billing plan with specified details like name, amount, currency, and features. ```bash API_BASE=http://localhost:8000 TOKEN="" curl -s -X POST "$API_BASE/payvia/plans" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Pro Monthly", "amount": 99.0, "currency": "USD", "interval": "monthly", "trial_days": 14, "features": { "locations": 3, "users": 10 } }' ``` -------------------------------- ### Payvia Configuration Structure Source: https://github.com/glueful/payvia/blob/main/README.md Example PHP array structure for Payvia configuration, showing default gateway, gateway settings, and feature flags. Environment variables are used for dynamic configuration. ```php return [ 'default_gateway' => env('PAYVIA_DEFAULT_GATEWAY', 'paystack'), 'gateways' => [ 'paystack' => [ 'enabled' => (bool) env('PAYVIA_PAYSTACK_ENABLED', true), 'driver' => 'paystack', 'secret_key' => env('PAYVIA_PAYSTACK_SECRET_KEY', env('PAYSTACK_SECRET_KEY', null)), 'base_url' => env('PAYVIA_PAYSTACK_BASE_URL', 'https://api.paystack.co'), 'timeout' => (int) env('PAYVIA_PAYSTACK_TIMEOUT', 15), ], // 'stripe' => [...], // 'flutterwave' => [...], ], 'features' => [ 'store_raw_payload' => (bool) env('PAYVIA_STORE_RAW_PAYLOAD', true), ], ]; ``` -------------------------------- ### List Billing Plans with Feature Filtering via cURL Source: https://github.com/glueful/payvia/blob/main/README.md Example of listing active billing plans, filtering by status and specific features using query parameters. ```bash curl -s "$API_BASE/payvia/plans?status=active&features_key=locations&features_value=1" \ -H "Authorization: Bearer $TOKEN" ``` -------------------------------- ### List Billing Plans using cURL Source: https://context7.com/glueful/payvia/llms.txt Send a GET request to `/payvia/plans` to list billing plans. Optional query parameters can filter by status, interval, currency, and features. Supports JSON field filtering on the `features` column. ```bash # List all active monthly USD plans that include at least 1 location curl -s "$API_BASE/payvia/plans?status=active&interval=monthly¤cy=USD&features_key=locations&features_value=1" \ -H "Authorization: Bearer $TOKEN" # Response (200): # { # "status": "success", # "data": [ # { # "uuid": "plan_abc123xyz", # "name": "Pro Monthly", # "description": "Pro plan billed monthly", # "amount": "99.00", # "currency": "USD", # "interval": "monthly", # "trial_days": 14, # "features": { "locations": 3, "users": 10, "api_calls": 50000 }, # "metadata": null, ``` -------------------------------- ### Implement Custom Stripe Payment Gateway Source: https://context7.com/glueful/payvia/llms.txt Implement the `PaymentGatewayInterface` to create a custom gateway. This example shows a Stripe gateway that verifies payment intents. Ensure the Stripe secret key is configured. ```php namespace App\Gateways; use Glueful\Bootstrap\ApplicationContext; use Glueful\Extensions\Payvia\Contracts\PaymentGatewayInterface; use Glueful\Http\Client as HttpClient; final class StripeGateway implements PaymentGatewayInterface { public function __construct( private HttpClient $http, private ApplicationContext $context, ) {} /** * @param array $options * @return array */ public function verify(string $reference, array $options = []): array { $config = (array) config($this->context, 'payvia.gateways.stripe', []); $secret = (string) ($config['secret_key'] ?? ''); if ($secret === '') { return ['status' => 'failed', 'reference' => $reference, 'message' => 'Missing Stripe secret key']; } try { $response = $this->http->get("https://api.stripe.com/v1/payment_intents/{$reference}", [ 'headers' => ['Authorization' => 'Bearer ' . $secret], ]); $data = $response->toArray(); return [ 'status' => $data['status'] === 'succeeded' ? 'success' : $data['status'], 'id' => $data['id'], 'reference' => $reference, 'amount' => (float) $data['amount'] / 100, 'currency' => strtoupper($data['currency']), 'message' => $data['status'], 'raw' => $data, ]; } catch (\Throwable $e) { return ['status' => 'failed', 'reference' => $reference, 'message' => $e->getMessage()]; } } } ``` -------------------------------- ### Confirm and Record Payment using PHP Source: https://github.com/glueful/payvia/blob/main/README.md PHP code to confirm and record a payment using the PaymentService. Handles success status for further actions like starting subscriptions. ```php use Glueful\Extensions\Payvia\Services\PaymentService; /** @var PaymentService $payments */ $payments = container()->get(PaymentService::class); $result = $payments->confirmAndRecord( reference: 'PSK_tx_ref_123456', gatewayName: 'paystack', // or null to use default context: [ 'user_uuid' => $userUuid, 'payable_type' => 'subscription', 'payable_id' => $subscriptionId, 'metadata' => [ 'source' => 'web_checkout', 'campaign' => 'black_friday', ], ] ); if (($result['payment_status'] ?? '') === 'success') { // Start subscription, mark invoice paid, etc. } ``` -------------------------------- ### GET /payvia/invoices - List Invoices (Paginated) Source: https://context7.com/glueful/payvia/llms.txt Retrieves a paginated list of invoices with support for various filters, including metadata. ```APIDOC ## GET /payvia/invoices — List Invoices (Paginated) Returns paginated invoices with optional filters. Supports JSON metadata filtering via `metadata_key` / `metadata_value`. ### Method GET ### Endpoint /payvia/invoices ### Parameters #### Query Parameters - **status** (string) - Optional - Filter invoices by status (e.g., 'paid', 'pending', 'draft', 'canceled'). - **user_uuid** (string) - Optional - Filter invoices by user UUID. - **billing_plan_uuid** (string) - Optional - Filter invoices by billing plan UUID. - **payable_type** (string) - Optional - Filter invoices by payable type. - **payable_id** (string) - Optional - Filter invoices by payable ID. - **metadata_key** (string) - Optional - Key for filtering within the JSON metadata. - **metadata_value** (string) - Optional - Value for filtering within the JSON metadata. - **page** (integer) - Optional - The page number for pagination (defaults to 1). - **per_page** (integer) - Optional - The number of items per page (defaults to a system defined value). ### Request Example ```bash curl -s "$API_BASE/payvia/invoices?status=paid&user_uuid=usr_abc123&metadata_key=period&metadata_value=2025-01&page=2&per_page=10" \ -H "Authorization: Bearer $TOKEN" ``` ### Response #### Success Response (200) - **status** (string) - Indicates the success of the operation. - **data** (array) - An array of invoice objects. - Each invoice object contains fields like `uuid`, `user_uuid`, `billing_plan_uuid`, `payable_type`, `payable_id`, `number`, `amount`, `currency`, `status`, `due_at`, `paid_at`, `metadata`, `created_at`, `updated_at`. - **total** (integer) - The total number of invoices matching the query. - **per_page** (integer) - The number of invoices per page. - **current_page** (integer) - The current page number. - **last_page** (integer) - The last page number. ``` -------------------------------- ### List Invoices (Paginated) Source: https://context7.com/glueful/payvia/llms.txt GET request to retrieve a paginated list of invoices. Supports filtering by status, user, and metadata key/value pairs. Includes pagination details in the response. ```bash # Page 2 of paid invoices for a user with period=2025-01 in metadata curl -s "$API_BASE/payvia/invoices?status=paid&user_uuid=usr_abc123&metadata_key=period&metadata_value=2025-01&page=2&per_page=10" \ -H "Authorization: Bearer $TOKEN" ``` -------------------------------- ### GET /payvia/plans - List Billing Plans Source: https://context7.com/glueful/payvia/llms.txt Retrieves a list of billing plans. Supports filtering by status, interval, currency, and features. Feature filtering can be done using `features_key` and `features_value` query parameters. ```APIDOC ## GET /payvia/plans — List Billing Plans Lists billing plans with optional filters. Supports JSON field filtering on the `features` column via `features_key` / `features_value` query parameters. ```bash # List all active monthly USD plans that include at least 1 location curl -s "$API_BASE/payvia/plans?status=active&interval=monthly¤cy=USD&features_key=locations&features_value=1" \ -H "Authorization: Bearer $TOKEN" # Response (200): # { # "status": "success", # "data": [ # { # "uuid": "plan_abc123xyz", # "name": "Pro Monthly", # "description": "Pro plan billed monthly", # "amount": "99.00", # "currency": "USD", # "interval": "monthly", # "trial_days": 14, # "features": { "locations": 3, "users": 10, "api_calls": 50000 }, # "metadata": null, ``` ``` -------------------------------- ### Create and List Billing Plans using PHP Source: https://github.com/glueful/payvia/blob/main/README.md PHP code demonstrating how to create a billing plan and then list active plans with specific feature criteria using the BillingPlanService. ```php use Glueful\Extensions\Payvia\Services\BillingPlanService; /** @var BillingPlanService $plans */ $plans = container()->get(BillingPlanService::class); // Create a plan $planUuid = $plans->create([ 'name' => 'Pro Monthly', 'description' => 'Pro plan billed monthly', 'amount' => 99.00, 'currency' => 'USD', 'interval' => 'monthly', 'trial_days' => 14, 'features' => [ 'locations' => 3, 'users' => 10, ], ]); // List active monthly plans with a feature flag $activePlans = $plans->list([ 'status' => 'active', 'interval' => 'monthly', 'features_contains' => [ 'key' => 'locations', 'value' => '1', // uses whereJsonContains under the hood ], ]); ``` -------------------------------- ### Enable Payvia Extension via CLI Source: https://github.com/glueful/payvia/blob/main/README.md Use the Glueful CLI to enable the Payvia extension, convenient for local development. ```bash php glueful extensions:enable Payvia ``` -------------------------------- ### Create a Billing Plan using cURL Source: https://context7.com/glueful/payvia/llms.txt Use a POST request to the `/payvia/plans` endpoint to create a new billing plan. The request body must include plan details like name, amount, currency, and interval. Rate-limited to 30 requests per 60 seconds. ```bash # Create a monthly Pro plan with feature limits curl -s -X POST "$API_BASE/payvia/plans" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ \ "name": "Pro Monthly", \ "description": "Pro plan billed monthly", \ "amount": 99.00, \ "currency": "USD", \ "interval": "monthly", \ "trial_days": 14, \ "features": { \ "locations": 3, \ "users": 10, \ "api_calls": 50000 \ }, \ "status": "active" \ }' # Response (201): # { \ # "status": "success", \ # "data": { "uuid": "plan_abc123xyz" } \ # } ``` -------------------------------- ### Enable Payvia Service Provider in Glueful Config Source: https://context7.com/glueful/payvia/llms.txt Enable the Payvia extension by registering its service provider in the Glueful configuration file. ```php // config/extensions.php return [ 'enabled' => [ Glueful\Extensions\Payvia\PayviaServiceProvider::class, ], ]; ``` -------------------------------- ### Full End-to-End Subscription Billing Flow Source: https://context7.com/glueful/payvia/llms.txt This snippet illustrates the complete subscription billing process. It requires importing the necessary Payvia service classes. Ensure the gateway reference and user context are correctly provided for payment confirmation. ```php use Glueful\Extensions\Payvia\Services\BillingPlanService; use Glueful\Extensions\Payvia\Services\InvoiceService; use Glueful\Extensions\Payvia\Services\PaymentService; $plans = container()->get(BillingPlanService::class); $invoices = container()->get(InvoiceService::class); $payments = container()->get(PaymentService::class); // 1. Define a plan (run once) $planUuid = $plans->create([ 'name' => 'Pro Monthly', 'amount' => 99.00, 'currency' => 'USD', 'interval' => 'monthly', 'features' => ['locations' => 3, 'users' => 10], ]); // 2. When subscription renewal is due, create an invoice $invoiceUuid = $invoices->create([ 'user_uuid' => $userUuid, 'billing_plan_uuid' => $planUuid, 'payable_type' => 'subscription', 'payable_id' => $subscriptionUuid, 'amount' => 99.00, 'currency' => 'USD', 'status' => 'pending', 'due_at' => date('Y-m-d H:i:s', strtotime('+7 days')), 'metadata' => ['period' => date('Y-m'), 'source' => 'auto_renewal'], ]); // 3. After the user completes checkout, confirm the payment $result = $payments->confirmAndRecord( reference: $paystackReference, // e.g. 'PSK_tx_ref_...' from frontend gatewayName: 'paystack', context: [ 'user_uuid' => $userUuid, 'payable_type' => 'subscription', 'payable_id' => $subscriptionUuid, 'metadata' => ['invoice_uuid' => $invoiceUuid, 'period' => date('Y-m')], ] ); // 4. On success, mark the invoice paid and activate the subscription if ($result['payment_status'] === 'success') { $invoices->markPaid($invoiceUuid); // ... activate subscription, send confirmation email, etc. } ``` -------------------------------- ### Full Payvia Configuration Structure Source: https://context7.com/glueful/payvia/llms.txt This is the complete structure for the `config/payvia.php` configuration file, showing all available options for default gateway, gateway-specific settings, and feature flags. ```php return [ 'default_gateway' => env('PAYVIA_DEFAULT_GATEWAY', 'paystack'), 'gateways' => [ 'paystack' => [ 'enabled' => (bool) env('PAYVIA_PAYSTACK_ENABLED', true), 'driver' => 'paystack', 'secret_key' => env('PAYVIA_PAYSTACK_SECRET_KEY', env('PAYSTACK_SECRET_KEY', null)), 'base_url' => env('PAYVIA_PAYSTACK_BASE_URL', 'https://api.paystack.co'), 'timeout' => (int) env('PAYVIA_PAYSTACK_TIMEOUT', 15), ], 'stripe' => [ 'enabled' => (bool) env('PAYVIA_STRIPE_ENABLED', false), 'driver' => 'stripe', 'secret_key' => env('PAYVIA_STRIPE_SECRET_KEY', null), ], 'flutterwave' => [ 'enabled' => (bool) env('PAYVIA_FLUTTERWAVE_ENABLED', false), 'driver' => 'flutterwave', 'secret_key' => env('PAYVIA_FLUTTERWAVE_SECRET_KEY', null), ], ], 'features' => [ 'store_raw_payload' => (bool) env('PAYVIA_STORE_RAW_PAYLOAD', true), ], ]; ``` -------------------------------- ### Enable Payvia Extension Manually Source: https://github.com/glueful/payvia/blob/main/README.md Add the Payvia Service Provider to the enabled list in your project's `config/extensions.php` file. ```php // config/extensions.php return [ 'enabled' => [ Glueful\Extensions\Payvia\PayviaServiceProvider::class, // other providers... ], // ... ]; ``` -------------------------------- ### Register Gateway Driver and Service Source: https://context7.com/glueful/payvia/llms.txt Register the custom gateway in `GatewayManager::$drivers` and as a service in `PayviaServiceProvider::services()` for the application to recognize it. ```php // In GatewayManager::$drivers array: private array $drivers = [ 'paystack' => PaystackGateway::class, 'stripe' => \App\Gateways\StripeGateway::class, ]; ``` ```php // In PayviaServiceProvider::services(): \App\Gateways\StripeGateway::class => [ 'class' => \App\Gateways\StripeGateway::class, 'shared' => true, 'autowire' => true, ], ``` -------------------------------- ### Payvia Configuration Environment Variables Source: https://github.com/glueful/payvia/blob/main/README.md Configure Payvia and its gateways (Paystack, Stripe, Flutterwave) using environment variables. Set the default gateway and provider-specific credentials. ```env # Default gateway (must exist in payvia.gateways) PAYVIA_DEFAULT_GATEWAY=paystack # Paystack PAYVIA_PAYSTACK_ENABLED=true PAYVIA_PAYSTACK_SECRET_KEY=sk_test_xxx PAYVIA_PAYSTACK_BASE_URL=https://api.paystack.co PAYVIA_PAYSTACK_TIMEOUT=15 # Stripe (example) PAYVIA_STRIPE_ENABLED=false PAYVIA_STRIPE_SECRET_KEY=sk_test_xxx # Flutterwave (example) PAYVIA_FLUTTERWAVE_ENABLED=false PAYVIA_FLUTTERWAVE_SECRET_KEY=flw_test_xxx # Whether to store full provider payload in raw_payload column PAYVIA_STORE_RAW_PAYLOAD=true ``` -------------------------------- ### Create Billing Plan Source: https://github.com/glueful/payvia/blob/main/README.md Creates a new billing plan with specified details. ```APIDOC ## POST /payvia/plans ### Description Creates a new billing plan with specified details, including name, amount, currency, and features. ### Method POST ### Endpoint /payvia/plans ### Request Body - **name** (string, required) - The name of the billing plan. - **amount** (number, required) - The cost of the plan. - **currency** (string, optional, default: `GHS`) - The currency of the amount. - **interval** (string, optional, default: `monthly`) - The billing interval (e.g., `monthly`, `yearly`). - **trial_days** (int, optional) - The number of trial days for the plan. - **features** (object, optional) - JSON object defining plan features or limits. - **metadata** (object, optional) - Additional metadata for the plan. - **status** (string, optional, default: `active`) - The status of the plan (`active` or `inactive`). ### Request Example ```json { "name": "Pro Monthly", "amount": 99.0, "currency": "USD", "interval": "monthly", "trial_days": 14, "features": { "locations": 3, "users": 10 } } ``` ``` -------------------------------- ### Create an Invoice Source: https://context7.com/glueful/payvia/llms.txt POST request to create a new invoice record. Auto-generates an invoice number if not provided. Requires amount, currency, user, and billing plan details. ```bash curl -s -X POST "$API_BASE/payvia/invoices" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "amount": 99.00, "currency": "USD", "user_uuid": "usr_abc123", "billing_plan_uuid": "plan_abc123xyz", "payable_type": "location_subscription", "payable_id": "loc_def456", "due_at": "2025-02-01 00:00:00", "status": "pending", "metadata": { "period": "2025-01", "source": "subscription_renewal" } }' ``` -------------------------------- ### Create, Update, and List Billing Plans Source: https://context7.com/glueful/payvia/llms.txt Use the BillingPlanService to programmatically manage billing plans. Supports creation, updates, and filtering by status, interval, and JSON features. ```php use Glueful\Extensions\Payvia\Services\BillingPlanService; /** @var BillingPlanService $plans */ $plans = container()->get(BillingPlanService::class); // Create $planUuid = $plans->create([ 'name' => 'Enterprise Yearly', 'amount' => 999.00, 'currency' => 'USD', 'interval' => 'yearly', 'trial_days' => 30, 'features' => ['locations' => 10, 'users' => 100], 'status' => 'active', ]); // Returns: "plan_ent789abc" // Update $plans->update($planUuid, ['amount' => 1099.00, 'features' => ['locations' => 15, 'users' => 150]]); // Returns: true // Filter with JSON feature check $activePlans = $plans->list([ 'status' => 'active', 'interval' => 'yearly', 'features_contains' => [ 'key' => 'locations', 'value' => '10', // uses whereJsonContains internally ], ]); // Returns: array of matching plan rows // Disable $plans->disable($planUuid); // Returns: true (sets status = 'inactive') ``` -------------------------------- ### Configure Payvia Environment Variables Source: https://context7.com/glueful/payvia/llms.txt Set environment variables in your .env file to configure the default gateway, enable specific payment providers, and set API keys and timeouts. ```env PAYVIA_DEFAULT_GATEWAY=paystack # Paystack (active by default) PAYVIA_PAYSTACK_ENABLED=true PAYVIA_PAYSTACK_SECRET_KEY=sk_live_xxxxxxxxxxxxxxxxxxxx PAYVIA_PAYSTACK_BASE_URL=https://api.paystack.co PAYVIA_PAYSTACK_TIMEOUT=15 # Stripe (driver stub - not yet implemented) PAYVIA_STRIPE_ENABLED=false PAYVIA_STRIPE_SECRET_KEY=sk_live_xxxxxxxxxxxxxxxxxxxx # Flutterwave (driver stub - not yet implemented) PAYVIA_FLUTTERWAVE_ENABLED=false PAYVIA_FLUTTERWAVE_SECRET_KEY=flw_live_xxxxxxxxxxxxxxxxxxxx # Store full provider verification JSON in raw_payload column PAYVIA_STORE_RAW_PAYLOAD=true ``` -------------------------------- ### Verify and Record Payments with PaymentService Source: https://context7.com/glueful/payvia/llms.txt Use `PaymentService::confirmAndRecord` for programmatic payment verification and persistence. It resolves the gateway, verifies the payment, enriches metadata, and saves the result. Handle potential `RuntimeException` for configuration or driver issues. ```php use Glueful\Extensions\Payvia\Services\PaymentService; /** @var PaymentService $payments */ $payments = container()->get(PaymentService::class); try { $result = $payments->confirmAndRecord( reference: 'PSK_tx_ref_20250101_abcdef', gatewayName: 'paystack', // null = use payvia.default_gateway context: [ 'user_uuid' => 'usr_abc123', 'payable_type' => 'subscription', 'payable_id' => 'sub_xyz789', 'metadata' => [ 'source' => 'web_checkout', 'campaign' => 'black_friday_2025', ], 'options' => [], // gateway-specific overrides (e.g. custom verify_url) ] ); if ($result['payment_status'] === 'success') { // Activate subscription, fulfil order, etc. echo "Paid {$result['amount']} {$result['currency']} via {$result['gateway']}\n"; // "Paid 99.00 USD via paystack" // $result also contains: // $result['reference'] => 'PSK_tx_ref_20250101_abcdef' // $result['message'] => 'Approved' // $result['verification'] => [...] full normalized gateway payload } else { // Handle failed/pending status echo "Payment status: {$result['payment_status']}\n"; } } catch (\RuntimeException $e) { // Gateway not configured, driver missing, etc. error_log('Payment error: ' . $e->getMessage()); } ``` -------------------------------- ### Confirm and Record Payment via API Source: https://context7.com/glueful/payvia/llms.txt Use the `POST /payvia/payments/confirm` endpoint to verify a transaction reference with the configured gateway and record it in the `payments` table. Requires authentication and is rate-limited. ```bash API_BASE=https://api.example.com TOKEN="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." # Confirm a Paystack payment linked to a subscription curl -s -X POST "$API_BASE/payvia/payments/confirm" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ \ "reference": "PSK_tx_ref_20250101_abcdef", \ "gateway": "paystack", \ "user_uuid": "usr_abc123", \ "payable_type": "subscription", \ "payable_id": "sub_xyz789", \ "metadata": { \ "source": "web_checkout", \ "campaign": "black_friday_2025" \ } \ }' ``` -------------------------------- ### Database Schema for Billing Plans in SQL Source: https://context7.com/glueful/payvia/llms.txt Defines the 'billing_plans' table for managing reusable plan catalog entries. Includes plan details, pricing, intervals, and features. ```sql -- billing_plans: reusable plan catalog CREATE TABLE billing_plans ( id BIGINT AUTO_INCREMENT PRIMARY KEY, uuid VARCHAR(12) UNIQUE NOT NULL, name VARCHAR(100) UNIQUE NOT NULL, description TEXT NULL, amount DECIMAL(12,2) NOT NULL, currency VARCHAR(10) DEFAULT 'GHS', interval VARCHAR(20) DEFAULT 'monthly', trial_days INT NULL, features JSON NULL, -- feature flags / usage limits metadata JSON NULL, status VARCHAR(20) DEFAULT 'active', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NULL ); ``` -------------------------------- ### POST /payvia/plans - Create a Billing Plan Source: https://context7.com/glueful/payvia/llms.txt Creates a new billing plan record. Returns the UUID of the newly created plan. This endpoint is rate-limited to 30 requests per 60 seconds. ```APIDOC ## POST /payvia/plans — Create a Billing Plan Creates a record in the `billing_plans` table. Returns the new plan UUID. Rate-limited to 30 requests per 60 seconds. ```bash # Create a monthly Pro plan with feature limits curl -s -X POST "$API_BASE/payvia/plans" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Pro Monthly", "description": "Pro plan billed monthly", "amount": 99.00, "currency": "USD", "interval": "monthly", "trial_days": 14, "features": { "locations": 3, "users": 10, "api_calls": 50000 }, "status": "active" }' # Response (201): # { # "status": "success", # "data": { "uuid": "plan_abc123xyz" } # } ``` ``` -------------------------------- ### Manage Invoices with InvoiceService Source: https://github.com/glueful/payvia/blob/main/README.md Use InvoiceService to create, mark as paid, and list invoices. Ensure the InvoiceService is retrieved from the container. Invoices can be linked to billing plans and payable entities, and metadata can be used for queryable context. ```php use Glueful\Extensions\Payvia\Services\InvoiceService; /** @var InvoiceService $invoices */ $invoices = container()->get(InvoiceService::class); // Create an invoice linked to a plan and payable entity $invoiceUuid = $invoices->create([ 'user_uuid' => $userUuid, 'billing_plan_uuid' => $planUuid, 'payable_type' => 'location_subscription', 'payable_id' => $locationUuid, 'amount' => 99.00, 'currency' => 'USD', 'status' => 'pending', 'metadata' => [ 'period' => '2025-01', 'source' => 'subscription_renewal', ], ]); // After a successful payment, mark the invoice as paid $invoices->markPaid($invoiceUuid); // List paid invoices for a user for a given period $userInvoices = $invoices->list([ 'user_uuid' => $userUuid, 'status' => 'paid', 'metadata_contains' => [ 'key' => 'period', 'value' => '2025-01', ], ]); ``` -------------------------------- ### Update a Billing Plan using cURL Source: https://context7.com/glueful/payvia/llms.txt Send a POST request to `/payvia/plans/update` with the `plan_uuid` and any fields to modify. All fields are optional. ```bash curl -s -X POST "$API_BASE/payvia/plans/update" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ \ "plan_uuid": "plan_abc123xyz", \ "amount": 129.00, \ "trial_days": 7, \ "features": { \ "locations": 5, \ "users": 20, \ "api_calls": 100000 \ } \ }' # Response (200): # { "status": "success", "data": { "updated": true } } ``` -------------------------------- ### List Invoices with Metadata Filtering via cURL Source: https://github.com/glueful/payvia/blob/main/README.md This cURL command shows how to list invoices, filtering by user UUID and specific metadata values. ```bash curl -s "$API_BASE/payvia/invoices?user_uuid=$USER_UUID&metadata_key=period&metadata_value=2025-01" \ -H "Authorization: Bearer $TOKEN" ``` -------------------------------- ### PaymentService::confirmAndRecord() Source: https://context7.com/glueful/payvia/llms.txt The primary entrypoint for verifying and persisting payments. It resolves the gateway, calls the gateway's verify method, enriches metadata, and saves the payment record. ```APIDOC ## PaymentService::confirmAndRecord() ### Description Verifies and persists payments by interacting with the configured payment gateway and repository. ### Method Signature ```php confirmAndRecord( string $reference, ?string $gatewayName = null, array $context = [] ): array ``` ### Parameters - **reference** (string) - Required - The payment reference identifier. - **gatewayName** (string|null) - Optional - The name of the gateway to use. If null, `payvia.default_gateway` is used. - **context** (array) - Optional - An array containing contextual information such as user details, payable type/ID, metadata, and gateway-specific options. - **user_uuid** (string) - Required - The UUID of the user making the payment. - **payable_type** (string) - Required - The type of entity the payment is for (e.g., 'subscription', 'order'). - **payable_id** (string) - Required - The ID of the payable entity. - **metadata** (array) - Optional - Additional metadata to be associated with the payment. - **options** (array) - Optional - Gateway-specific overrides or configurations. ### Request Example ```php use Glueful\Extensions\Payvia\Services\PaymentService; $payments = container()->get(PaymentService::class); try { $result = $payments->confirmAndRecord( reference: 'PSK_tx_ref_20250101_abcdef', gatewayName: 'paystack', context: [ 'user_uuid' => 'usr_abc123', 'payable_type' => 'subscription', 'payable_id' => 'sub_xyz789', 'metadata' => [ 'source' => 'web_checkout', 'campaign' => 'black_friday_2025', ], 'options' => [], ] ); if ($result['payment_status'] === 'success') { echo "Paid {$result['amount']} {$result['currency']} via {$result['gateway']}\\n"; } else { echo "Payment status: {$result['payment_status']}\\n"; } } catch (\RuntimeException $e) { error_log('Payment error: ' . $e->getMessage()); } ``` ### Response On success, returns an array containing payment details. On failure or exception, an error is logged or an exception is thrown. #### Success Response (Example) ```json { "payment_status": "success", "amount": 99.00, "currency": "USD", "gateway": "paystack", "reference": "PSK_tx_ref_20250101_abcdef", "message": "Approved", "verification": { ... full normalized gateway payload ... } } ``` #### Error Handling - Throws `\RuntimeException` for issues like missing gateway configuration or drivers. - Payment failures will result in a `payment_status` other than 'success'. ``` -------------------------------- ### Create Invoice Source: https://context7.com/glueful/payvia/llms.txt Creates a new invoice with specified details and returns its unique identifier. The invoice is initially set to a 'pending' status. ```APIDOC ## create ### Description Creates a new invoice with the provided details. The invoice will be initialized with a 'pending' status. ### Method `InvoiceService::create(array $attributes)` ### Parameters #### Request Body - **user_uuid** (string) - Required - The UUID of the user associated with the invoice. - **billing_plan_uuid** (string) - Required - The UUID of the billing plan. - **payable_type** (string) - Required - The type of entity the invoice is for (e.g., 'location_subscription'). - **payable_id** (string) - Required - The ID of the payable entity. - **amount** (float) - Required - The invoice amount. - **currency** (string) - Required - The currency of the invoice (e.g., 'USD'). - **status** (string) - Required - The initial status of the invoice (e.g., 'pending'). - **due_at** (string) - Required - The due date for the invoice in 'YYYY-MM-DD HH:MM:SS' format. - **metadata** (array) - Optional - Additional metadata associated with the invoice. ### Response #### Success Response (200) - **invoiceUuid** (string) - The unique identifier of the newly created invoice (e.g., "inv_ghi789jkl"). ``` -------------------------------- ### Disable a Billing Plan using cURL Source: https://context7.com/glueful/payvia/llms.txt Use a POST request to `/payvia/plans/disable` with the `plan_uuid` to set the plan's status to `inactive`. This prevents new subscriptions but does not affect existing ones. ```bash curl -s -X POST "$API_BASE/payvia/plans/disable" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "plan_uuid": "plan_abc123xyz" }' # Response (200): # { "status": "success", "data": { "disabled": true } } ``` -------------------------------- ### GatewayManager::gateway() Source: https://context7.com/glueful/payvia/llms.txt Resolves and returns a payment gateway instance based on the provided key. It caches instances per request and throws an exception if the gateway is not configured or disabled. ```APIDOC ## GatewayManager::gateway() ### Description Resolves and returns a `PaymentGatewayInterface` instance by gateway key, reading configuration from `payvia.gateways`. Throws `RuntimeException` if the key is unknown or the gateway is disabled. Instances are cached per request. ### Method Signature ```php gateway(string $gatewayKey): PaymentGatewayInterface ``` ### Parameters - **gatewayKey** (string) - Required - The key identifying the payment gateway (e.g., 'paystack', 'stripe'). ### Request Example ```php use Glueful\Extensions\Payvia\GatewayManager; use Glueful\Extensions\Payvia\Contracts\PaymentGatewayInterface; $manager = container()->get(GatewayManager::class); // Resolve the Paystack gateway $gateway = $manager->gateway('paystack'); // Returns a PaystackGateway instance // Example of calling verify directly on the gateway instance $verification = $gateway->verify('PSK_tx_ref_20250101_abcdef', [ // 'verify_url' => 'https://api.paystack.co/transaction/verify/PSK_tx_ref_20250101_abcdef', ]); // Example of handling a disabled gateway try { $manager->gateway('stripe'); } catch (\RuntimeException $e) { // "Payvia: gateway 'stripe' is not configured or disabled." error_log($e->getMessage()); } ``` ### Response Returns an instance of `PaymentGatewayInterface` upon successful resolution. #### Success Response An object implementing `PaymentGatewayInterface` (e.g., `PaystackGateway`). #### Gateway Verification Response Example (Success) ```json { "status": "success", "id": 9876543, "reference": "PSK_tx_ref_20250101_abcdef", "amount": 99.00, "currency": "USD", "message": "Approved", "raw": { ... full gateway API response ... } } ``` #### Gateway Verification Response Example (Error) ```json { "status": "failed", "reference": "PSK_tx_ref_20250101_abcdef", "message": "Paystack verification request failed: ..." } ``` #### Error Handling - Throws `\RuntimeException` if the `gatewayKey` is unknown or the corresponding gateway is disabled in the configuration. ``` -------------------------------- ### Confirm and Record Payment API Request Source: https://github.com/glueful/payvia/blob/main/README.md Send a POST request to `/payvia/payments/confirm` with transaction details to verify and record a payment. The `gateway` parameter is optional; if omitted, the default gateway is used. ```json { "reference": "provider transaction reference", "gateway": "gateway key from config/payvia.php", "user_uuid": "UUID of the paying user", "payable_type": "logical type of the thing being paid for", "payable_id": "identifier of that thing in its own domain", "metadata": { "app-level": "context" }, "options": { "gateway-specific": "options" } } ``` -------------------------------- ### Manage Invoices with InvoiceService in PHP Source: https://context7.com/glueful/payvia/llms.txt Use the InvoiceService to create, update, and list invoices programmatically. Ensure the InvoiceService is correctly injected into your container. ```php use Glueful\Extensions\Payvia\Services\InvoiceService; /** @var InvoiceService $invoices */ $invoices = container()->get(InvoiceService::class); // Create a pending invoice $invoiceUuid = $invoices->create([ 'user_uuid' => 'usr_abc123', 'billing_plan_uuid' => 'plan_abc123xyz', 'payable_type' => 'location_subscription', 'payable_id' => 'loc_def456', 'amount' => 99.00, 'currency' => 'USD', 'status' => 'pending', 'due_at' => '2025-02-01 00:00:00', 'metadata' => ['period' => '2025-01', 'source' => 'subscription_renewal'], ]); // Returns: "inv_ghi789jkl" // After successful payment confirmation $invoices->markPaid($invoiceUuid); // Or with an explicit timestamp: $invoices->markPaid($invoiceUuid, new \DateTimeImmutable('2025-01-15 14:30:00')); // Returns: true // Cancel an invoice $invoices->markCanceled($invoiceUuid); // Returns: true // Paginated list with filters $page = $invoices->list( page: 1, perPage: 20, filters: [ 'status' => 'paid', 'user_uuid' => 'usr_abc123', 'metadata_contains' => [ 'key' => 'period', 'value' => '2025-01', ], ] ); // Returns paginated structure: // [ // 'data' => [ [...], [...], ... ], // 'total' => 42, // 'per_page' => 20, // 'current_page' => 1, // 'last_page' => 3, // ] ``` -------------------------------- ### Database Schema for Invoices in SQL Source: https://context7.com/glueful/payvia/llms.txt Defines the 'invoices' table for tracking individual invoice records. Includes fields for user, billing plan, amount, status, and due dates. ```sql -- invoices: trackable invoice records CREATE TABLE invoices ( id BIGINT AUTO_INCREMENT PRIMARY KEY, uuid VARCHAR(12) UNIQUE NOT NULL, user_uuid VARCHAR(12) NULL REFERENCES users(uuid) ON DELETE CASCADE, billing_plan_uuid VARCHAR(12) NULL, payable_type VARCHAR(100) NULL, payable_id VARCHAR(255) NULL, number VARCHAR(50) UNIQUE NOT NULL, -- auto-generated if omitted amount DECIMAL(12,2) NOT NULL, currency VARCHAR(10) DEFAULT 'GHS', status VARCHAR(20) DEFAULT 'draft', -- draft|pending|paid|canceled|failed due_at TIMESTAMP NULL, paid_at TIMESTAMP NULL, metadata JSON NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NULL ); ``` -------------------------------- ### Resolve Payment Gateway Driver with GatewayManager Source: https://context7.com/glueful/payvia/llms.txt Use `GatewayManager::gateway()` to resolve a `PaymentGatewayInterface` instance by its key. Configuration is read from `payvia.gateways`. Throws `RuntimeException` if the gateway is unknown or disabled. Instances are cached per request. ```php use Glueful\Extensions\Payvia\GatewayManager; use Glueful\Extensions\Payvia\Contracts\PaymentGatewayInterface; /** @var GatewayManager $manager */ $manager = container()->get(GatewayManager::class); // Resolve the Paystack gateway directly $gateway = $manager->gateway('paystack'); // returns PaystackGateway instance // Call verify() directly (bypasses PaymentService persistence) $verification = $gateway->verify('PSK_tx_ref_20250101_abcdef', [ // optional: override the verify URL // 'verify_url' => 'https://api.paystack.co/transaction/verify/PSK_tx_ref_20250101_abcdef', ]); // $verification shape on success: // [ // 'status' => 'success', // 'id' => 9876543, // 'reference' => 'PSK_tx_ref_20250101_abcdef', // 'amount' => 99.00, // converted from kobo to major unit // 'currency' => 'USD', // 'message' => 'Approved', // 'raw' => [ ... full Paystack API response ... ], // ] // Error shape: // [ // 'status' => 'failed', // 'reference' => 'PSK_tx_ref_20250101_abcdef', // 'message' => 'Paystack verification request failed: ...', // ] try { $manager->gateway('stripe'); // throws if PAYVIA_STRIPE_ENABLED=false } catch (\RuntimeException $e) { // "Payvia: gateway 'stripe' is not configured or disabled." } ```