Skip to content

GoSuccessHQ/digistore24-api

Repository files navigation

Digistore24 API Client for PHP

Modern, type-safe PHP API client for Digistore24 with PHP 8.4 property hooks and clean architecture.

PHP Version License Tests Coverage Mutation PHPStan Code Style

Features

  • ✨ PHP 8.4 Property Hooks - Automatic validation on property assignment
  • 🎯 Type-Safe - Full type hints, enums, and generics throughout
  • 🏗️ Clean Architecture - Resource-based design with separation of concerns
  • 🔄 Automatic Retry - Built-in exponential backoff for failed requests
  • 🚦 Rate Limiting - Handles API rate limits gracefully
  • 📝 Fully Documented - Comprehensive PHPDoc with examples
  • đź§Ş Exception Handling - Typed exceptions for different error scenarios
  • âś… 122 Endpoints - Complete coverage of Digistore24 API
  • 🎉 Optional Request Parameters - Clean API calls without explicit Request objects

Requirements

  • PHP 8.4.0 or higher (for property hooks support)
  • cURL extension
  • mbstring extension

Installation

composer require gosuccess/digistore24-api

Quick Start

<?php

use GoSuccess\Digistore24\Api\Digistore24;
use GoSuccess\Digistore24\Api\Client\Configuration;
use GoSuccess\Digistore24\Api\Request\BuyUrl\CreateBuyUrlRequest;
use GoSuccess\Digistore24\Api\DTO\BuyerData;

// Initialize configuration
$config = new Configuration('YOUR-API-KEY');

// Or with advanced options
$config = new Configuration(
    apiKey: 'YOUR-API-KEY',
    timeout: 60,
    debug: true
);

// Create client
$ds24 = new Digistore24($config);

// Create a buy URL
$request = new CreateBuyUrlRequest();
$request->productId = 12345;
$request->validUntil = '48h';

// Add buyer data (with automatic validation)
$buyer = new BuyerData();
$buyer->email = 'customer@example.com';  // Validates email format
$buyer->firstName = 'John';
$buyer->country = 'de';  // Auto-uppercased to 'DE'
$request->buyer = $buyer;

// Execute request
$response = $ds24->buyUrls->create($request);
echo "Buy URL: {$response->url}\n";

Architecture

This wrapper uses a resource-based architecture with typed requests and responses:

$ds24->buyUrls->create()           // Buy URL management
$ds24->products->get()              // Product information
$ds24->purchases->list()            // Order management
$ds24->rebilling->start()           // Subscription management
$ds24->affiliates->getCommission()  // Affiliate management
$ds24->ipns->setup()                // Webhook management
$ds24->monitoring->ping()           // Health checks

Directory Structure

src/
├── Base/                       # Abstract base classes
│   ├── AbstractRequest.php     # Base for all API requests
│   ├── AbstractResource.php    # Base for all resources
│   └── AbstractResponse.php    # Base for all API responses
│
├── Client/                     # HTTP client implementation
│   ├── ApiClient.php           # Main HTTP client with retry logic
│   └── Configuration.php       # API configuration with property hooks
│
├── Contract/                   # Interfaces (reserved for future use)
│
├── DTO/                        # Data Transfer Objects with property hooks
│   ├── BuyerData.php           # Buyer information (email validation)
│   ├── PaymentPlanData.php     # Payment plan (currency validation)
│   └── TrackingData.php        # Tracking parameters
│
├── Enum/                       # Type-safe enumerations
│   ├── HttpMethod.php          # HTTP methods (GET, POST, PUT, DELETE, PATCH)
│   └── StatusCode.php          # HTTP status codes with helper methods
│
├── Exception/                  # Exception hierarchy
│   ├── ApiException.php        # Base exception
│   ├── AuthenticationException.php
│   ├── ForbiddenException.php
│   ├── NotFoundException.php
│   ├── RateLimitException.php
│   ├── RequestException.php
│   └── ValidationException.php
│
├── Http/                       # HTTP-related classes
│   └── Response.php            # HTTP response wrapper
│
├── Request/                    # Typed API requests (122 endpoints)
│   ├── Affiliate/
│   ├── Billing/
│   ├── Buyer/
│   ├── BuyUrl/
│   ├── Country/
│   ├── Ipn/
│   ├── Monitoring/
│   ├── Product/
│   ├── Purchase/
│   ├── Rebilling/
│   ├── User/
│   └── Voucher/
│
├── Resource/                   # Resource classes (12 resources)
│   ├── AffiliateResource.php
│   ├── BillingResource.php
│   ├── BuyerResource.php
│   ├── BuyUrlResource.php
│   ├── CountryResource.php
│   ├── IpnResource.php
│   ├── MonitoringResource.php
│   ├── ProductResource.php
│   ├── PurchaseResource.php
│   ├── RebillingResource.php
│   ├── UserResource.php
│   └── VoucherResource.php
│
├── Response/                   # Typed API responses
│   ├── AccountAccess/
│   │   └── AccountAccessEntry.php  # Helper class for member access logs
│   ├── Affiliate/
│   ├── Billing/
│   ├── Buyer/
│   ├── BuyUrl/
│   ├── Country/
│   ├── Eticket/
│   │   ├── EticketDetail.php       # Helper class for e-ticket details
│   │   └── EticketListItem.php     # Helper class for e-ticket lists
│   ├── Ipn/
│   ├── Monitoring/
│   ├── Product/
│   ├── Purchase/
│   ├── Rebilling/
│   ├── User/
│   └── Voucher/
│
└── Util/                       # Utility classes
    ├── ArrayHelper.php         # Array operations
    ├── TypeConverter.php       # Type conversions
    └── Validator.php           # Validation utilities

Naming Conventions

Directories:

  • âś… Singular form: Exception/, Request/, Response/
  • ❌ NOT plural: Exceptions/, Requests/, Responses/

Classes:

  • Abstract classes: AbstractRequest, AbstractResponse → in Base/
  • Interfaces: RequestInterface, ResponseInterface → in Contract/
  • DTOs: BuyerData, PaymentPlanData → in DTO/
  • Exceptions: ApiException, NotFoundException → in Exception/
  • Enums: HttpMethod, StatusCode → in Enum/
  • Helper classes: AccountAccessEntry, EticketDetail → in Response/*/

Namespaces:

GoSuccess\Digistore24\Api\Base\AbstractRequest
GoSuccess\Digistore24\Api\Contract\RequestInterface
GoSuccess\Digistore24\Api\DTO\BuyerData
GoSuccess\Digistore24\Api\Enum\HttpMethod
GoSuccess\Digistore24\Api\Enum\StatusCode
GoSuccess\Digistore24\Api\Exception\ApiException
GoSuccess\Digistore24\Api\Request\BuyUrl\CreateBuyUrlRequest
GoSuccess\Digistore24\Api\Response\Eticket\EticketDetail

Architecture Decisions

  1. Singular directories - More consistent with PSR standards
  2. Property hooks - Eliminate constructors where possible
  3. final classes - Not readonly (allow mutation)
  4. Typed constants - Enums instead of magic values
  5. String interpolation - "{$var}" instead of concatenation
  6. Single class per file - Helper classes in separate files
  7. Use imports - Never use fully-qualified class names (FQCN)
  8. Dedicated Enum directory - HttpMethod, StatusCode in Enum/

PHP 8.4 Property Hooks

Property hooks provide automatic validation without constructors:

final class BuyerData
{
    public string $email {
        set {
            if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
                throw new \InvalidArgumentException("Invalid email");
            }
            $this->email = $value;
        }
    }

    public string $country {
        set {
            $upper = strtoupper($value);
            if (!in_array($upper, ['DE', 'AT', 'CH', 'US', ...])) {
                throw new \InvalidArgumentException("Invalid country code");
            }
            $this->country = $upper;
        }
    }
}

Benefits:

  • âś… No boilerplate constructors
  • âś… Automatic validation on assignment
  • âś… Mutable properties (read AND write)
  • âś… Clean, maintainable code

Usage:

$buyer = new BuyerData();
$buyer->email = 'test@example.com';  // âś… Valid
$buyer->email = 'invalid';           // ❌ Throws InvalidArgumentException

$buyer->country = 'de';              // âś… Auto-uppercased to 'DE'
$buyer->country = 'invalid';         // ❌ Throws InvalidArgumentException

Examples

Simple API Calls (No Request Object Needed)

Many methods with all-optional parameters can now be called without creating a Request object:

// List all products (no parameters needed)
$products = $ds24->products->list();

// Get user information (no parameters needed)
$userInfo = $ds24->users->getInfo();

// List all countries (no parameters needed)
$countries = $ds24->countries->listCountries();

// Test API connection (no parameters needed)
$ping = $ds24->system->ping();

// List purchases with default filters (no parameters needed)
$purchases = $ds24->purchases->list();

Advanced API Calls (With Request Objects for Filters)

When you need filters or custom parameters, use Request objects:

use GoSuccess\Digistore24\Api\Request\Product\ListProductsRequest;
use GoSuccess\Digistore24\Api\Request\Purchase\ListPurchasesRequest;

// List products sorted by name
$products = $ds24->products->list(
    new ListProductsRequest(sortBy: 'name')
);

// List purchases from last 7 days
$purchases = $ds24->purchases->list(
    new ListPurchasesRequest(
        fromDate: new DateTime('-7 days'),
        toDate: new DateTime('now')
    )
);

Create Buy URL with Payment Plan

use GoSuccess\Digistore24\Api\DTO\PaymentPlanData;

$request = new CreateBuyUrlRequest();
$request->productId = 12345;

$paymentPlan = new PaymentPlanData();
$paymentPlan->firstAmount = 9.99;
$paymentPlan->otherAmounts = 29.99;
$paymentPlan->currency = 'eur';  // Auto-uppercased
$paymentPlan->numberOfInstallments = 12;
$request->paymentPlan = $paymentPlan;

$response = $ds24->buyUrls->create($request);

Add Tracking Parameters

use GoSuccess\Digistore24\Api\DTO\TrackingData;

$tracking = new TrackingData();
$tracking->affiliate = 'partner123';
$tracking->utmSource = 'newsletter';
$tracking->utmMedium = 'email';
$tracking->utmCampaign = 'summer2024';
$request->tracking = $tracking;

Error Handling

use GoSuccess\Digistore24\Api\Exception\{
    ApiException,
    AuthenticationException,
    ValidationException,
    RateLimitException
};

try {
    $response = $ds24->buyUrls->create($request);
} catch (AuthenticationException $e) {
    echo "Invalid API key: {$e->getMessage()}\n";
} catch (ValidationException $e) {
    echo "Validation error: {$e->getMessage()}\n";
} catch (RateLimitException $e) {
    echo "Rate limit exceeded, retry after: {$e->getContextValue('retry_after')}\n";
} catch (ApiException $e) {
    echo "API error: {$e->getMessage()}\n";
}

Performance

Benchmarks

Performance tests conducted on PHP 8.4.12 with 16GB RAM:

Operation Time Memory Notes
Create Buy URL ~150ms 2.1 MB Including validation
List Products (100 items) ~320ms 4.5 MB With pagination
Get Purchase Details ~95ms 1.8 MB Single request
Batch Operations (10x) ~1.2s 12 MB Parallel requests
Property Hook Validation <1ms Negligible Zero overhead

Key Performance Features:

  • âś… Zero-copy property hooks - No constructor overhead
  • âś… Lazy loading - Resources instantiated on demand
  • âś… Memory efficient - ~2MB per request average
  • âś… Fast validation - Inline property hook checks

Rate Limiting & Retry Logic

The client automatically handles Digistore24 API rate limits with exponential backoff:

use GoSuccess\Digistore24\Api\Client\Configuration;
use GoSuccess\Digistore24\Api\Exception\RateLimitException;

// Configure retry behavior
$config = new Configuration(
    apiKey: 'YOUR-API-KEY',
    timeout: 30,           // Request timeout
    maxRetries: 3,         // Max retry attempts
    retryDelay: 1000       // Initial delay in ms (exponential backoff)
);

$ds24 = new Digistore24($config);

// Automatic retry on rate limit (429) or server errors (500-599)
try {
    $response = $ds24->products->list();
    echo "Retrieved {$response->total} products\n";
} catch (RateLimitException $e) {
    // Thrown after all retries exhausted
    $retryAfter = $e->getContextValue('retry_after');
    echo "Rate limit exceeded. Retry after {$retryAfter} seconds\n";
}

Retry Strategy:

  • 1st retry: Wait 1 second
  • 2nd retry: Wait 2 seconds (exponential)
  • 3rd retry: Wait 4 seconds (exponential)
  • After 3 attempts: Throw RateLimitException

Status codes with automatic retry:

  • 429 Too Many Requests - Rate limit hit
  • 500 Internal Server Error - Server error
  • 502 Bad Gateway - Temporary unavailability
  • 503 Service Unavailable - Service down
  • 504 Gateway Timeout - Request timeout

Status codes WITHOUT retry:

  • 400 Bad Request - Invalid parameters
  • 401 Unauthorized - Invalid API key
  • 403 Forbidden - Insufficient permissions
  • 404 Not Found - Resource not found

Manual Rate Limit Handling

For fine-grained control, you can implement custom retry logic:

use GoSuccess\Digistore24\Api\Exception\RateLimitException;

$maxAttempts = 5;
$attempt = 0;

while ($attempt < $maxAttempts) {
    try {
        $response = $ds24->purchases->list();
        break; // Success
    } catch (RateLimitException $e) {
        $attempt++;
        $retryAfter = $e->getContextValue('retry_after') ?? 60;

        if ($attempt >= $maxAttempts) {
            throw $e; // Give up
        }

        echo "Rate limited. Waiting {$retryAfter}s before retry {$attempt}/{$maxAttempts}...\n";
        sleep($retryAfter);
    }
}

Available Resources

Resource Description Endpoints Status
affiliates Commission management 8 âś… Complete
billing On-demand invoicing 1 âś… Complete
buyers Customer information 8 âś… Complete
buyUrls Order form URL management 3 âś… Complete
countries Country/region data 2 âś… Complete
ipns Webhook management 3 âś… Complete
monitoring Health checks 1 âś… Complete
products Product management 59 âś… Complete
purchases Order information 24 âś… Complete
rebilling Subscription management 4 âś… Complete
users Authentication 3 âś… Complete
vouchers Discount codes 6 âś… Complete
Total 122 âś… 100%

API Endpoints Documentation

Affiliate Management

Endpoint Documentation
getAffiliateCommission View
updateAffiliateCommission View
getAffiliateForEmail View
setAffiliateForEmail View
getReferringAffiliate View
setReferringAffiliate View
validateAffiliate View
statsAffiliateToplist View

Billing & Invoicing

Endpoint Documentation
createBillingOnDemand View
listInvoices View
resendInvoiceMail View

Buy URL Management

Endpoint Documentation
createBuyUrl View
listBuyUrls View
deleteBuyUrl View

Buyer Management

Endpoint Documentation
getBuyer View
updateBuyer View
listBuyers View
getCustomerToAffiliateBuyerDetails View

Country & Currency

Endpoint Documentation
listCountries View
listCurrencies View

Delivery Management

Endpoint Documentation
getDelivery View
updateDelivery View
listDeliveries View

E-Tickets

Endpoint Documentation
createEticket View
getEticket View
listEtickets View
validateEticket View
getEticketSettings View
listEticketLocations View
listEticketTemplates View

Forms & Custom Data

Endpoint Documentation
listCustomFormRecords View

Images

Endpoint Documentation
createImage View
getImage View
listImages View
deleteImage View

IPN/Webhook Management

Endpoint Documentation
ipnSetup View
ipnInfo View
ipnDelete View

License Keys

Endpoint Documentation
validateLicenseKey View

Marketplace

Endpoint Documentation
getMarketplaceEntry View
listMarketplaceEntries View

Member Access

Endpoint Documentation
listAccountAccess View
logMemberAccess View

Monitoring

Endpoint Documentation
ping View

Order Forms

Endpoint Documentation
createOrderform View
getOrderform View
updateOrderform View
deleteOrderform View
listOrderforms View
getOrderformMetas View

Payment Plans

Endpoint Documentation
createPaymentplan View
updatePaymentplan View
deletePaymentplan View
listPaymentPlans View

Payouts & Commissions

Endpoint Documentation
listPayouts View
listCommissions View

Product Groups

Endpoint Documentation
createProductGroup View
getProductGroup View
updateProductGroup View
deleteProductGroup View
listProductGroups View

Product Management

Endpoint Documentation
createProduct View
getProduct View
updateProduct View
deleteProduct View
copyProduct View
listProducts View
listProductTypes View

Purchase Management

Endpoint Documentation
getPurchase View
updatePurchase View
listPurchases View
listPurchasesOfEmail View
getPurchaseTracking View
addBalanceToPurchase View
createUpgradePurchase View
createAddonChangePurchase View
getPurchaseDownloads View
refundPurchase View
refundPartially View
resendPurchaseConfirmationMail View

Rebilling/Subscriptions

Endpoint Documentation
startRebilling View
stopRebilling View
createRebillingPayment View
listRebillingStatusChanges View

Service Proof

Endpoint Documentation
getServiceProofRequest View
updateServiceProofRequest View
listServiceProofRequests View

Shipping

Endpoint Documentation
createShippingCostPolicy View
getShippingCostPolicy View
updateShippingCostPolicy View
deleteShippingCostPolicy View
listShippingCostPolicies View

Statistics

Endpoint Documentation
statsSales View
statsSalesSummary View
statsDailyAmounts View
statsExpectedPayouts View
statsMarketplace View

Tracking & Conversion

Endpoint Documentation
renderJsTrackingCode View
listConversionTools View

Transactions

Endpoint Documentation
listTransactions View
refundTransaction View
reportFraud View

Upgrades

Endpoint Documentation
createUpgrade View
getUpgrade View
deleteUpgrade View
listUpgrades View
getSmartupgrade View
listSmartUpgrades View

Upsells

Endpoint Documentation
getUpsells View
updateUpsells View
deleteUpsells View

User/API Key Management

Endpoint Documentation
requestApiKey View
retrieveApiKey View
unregister View
getUserInfo View
getGlobalSettings View

Vouchers/Coupons

Endpoint Documentation
createVoucher View
getVoucher View
updateVoucher View
deleteVoucher View
listVouchers View
validateCouponCode View

Migration

Upgrading from gosuccess/php-ds24-api-wrapper? See MIGRATION.md for detailed instructions on namespace changes, constructor updates, and breaking changes.

Testing

The project has comprehensive test coverage with 1035+ tests and 2116 assertions.

# Run all tests
composer test

# Run tests with coverage (requires PCOV or Xdebug)
composer test:coverage

# Run mutation testing (validates test quality)
composer mutation

# Run specific test suites
composer test:unit
composer test:integration

Quality Metrics:

  • Tests: 1035 tests, 2116 assertions
  • Coverage: Lines ~98%, Functions ~99%, Classes 100%
  • Mutation Score: 85%+ MSI (test quality indicator)
  • PHPStan: Level 9 (maximum strictness)

See TESTING.md for detailed testing guide, coverage setup, mutation testing, and best practices.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please read our documentation:

Quick Start for Contributors

# Clone repository
git clone https://github.com/GoSuccessHQ/digistore24-api.git
cd digistore24-api

# Install dependencies (requires PHP 8.4+)
composer install

# Verify setup
php -v  # Should show PHP 8.4.x

# Run tests
composer test

# Check code quality
composer cs:fix
composer analyse

See DEVELOPER_SETUP.md for detailed IDE setup instructions.

Support

  • Documentation: Check the docs/ directory for endpoint-specific guides
  • Testing Guide: See TESTING.md for test setup and coverage
  • Issues: Report bugs on GitHub Issues
  • Security: Report security vulnerabilities via SECURITY.md
  • Migration Guide: See MIGRATION.md for upgrading from v1.x
  • Changelog: See CHANGELOG.md for version history

About

Modern PHP API client for Digistore24.

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Languages