NovinkaZverejnili sme 50+ Laravel balíkov ako open source
Custom AI apps, agents and automation — Roundly ConsultingRoundly
Všetky balíky

Balík funguje bez akejkoľvek konfigurácie, no žiadny poskytovateľ nič neoverí, kým nenastavíte jeho prístupové údaje. Publikovaný config/purchases.php v plnom rozsahu:

/*
 | Every on/off switch below is read from the environment as a string, so each is
 | read strictly: 1/true/on/yes are on, 0/false/off/no are off, unset or blank
 | (KEY=) keeps the documented default (for push authentication that is ON —
 | fail-closed), and anything else throws an InvalidConfigurationException naming
 | the key. Every other setting is strict too: blank means not set, so the default
 | applies, while a duration such as the Stripe tolerance must be a whole number
 | and URLs and queue names must be strings.
 */
return [
    'models' => [
        'purchase' => \RoundlyConsulting\Purchases\Models\Purchase::class,
        'purchase-item' => \RoundlyConsulting\Purchases\Models\PurchaseItem::class,
        'purchase-refund' => \RoundlyConsulting\Purchases\Models\PurchaseRefund::class,
        'purchase-notification' => \RoundlyConsulting\Purchases\Models\PurchaseNotification::class,
        'subscription' => \RoundlyConsulting\Purchases\Models\Subscription::class,
        'subscription-item' => \RoundlyConsulting\Purchases\Models\SubscriptionItem::class,
    ],

    'providers' => [
        \RoundlyConsulting\Purchases\Providers\Apple\Apple::class,
        \RoundlyConsulting\Purchases\Providers\Google\Google::class,
        \RoundlyConsulting\Purchases\Providers\Stripe\Stripe::class,
    ],

    // Owner morph key type: "bigint", "uuid" or "ulid" — anything else throws.
    'key_type' => env('PURCHASES_KEY_TYPE', 'bigint'),

    // Log every verified raw payload to purchase_notifications before reducing it.
    'audit' => [
        'enabled' => env('PURCHASES_AUDIT_ENABLED', true),
    ],

    // Persist verified notifications on a queue; the webhook still 204s immediately.
    'queue' => [
        'enabled' => env('PURCHASES_QUEUE_ENABLED', false),
        'connection' => env('PURCHASES_QUEUE_CONNECTION'),
        'queue' => env('PURCHASES_QUEUE_NAME'),
    ],

    'routes' => [
        'enabled' => env('PURCHASES_ROUTES_ENABLED', false),
        'prefix' => env('PURCHASES_ROUTES_PREFIX', 'purchases'),
        'middleware' => ['api'],
    ],

    'settings' => [
        'apple' => [
            // The one App Store app this host accepts notifications and transactions for.
            'bundle_id' => env('PURCHASES_APPLE_BUNDLE_ID'),
            'app_apple_id' => env('PURCHASES_APPLE_APP_APPLE_ID'),

            // Production unless switched on.
            'sandbox' => env('PURCHASES_APPLE_SANDBOX', false),
            'url' => [
                'live' => env('PURCHASES_APPLE_LIVE_URL', 'https://buy.itunes.apple.com'),
                'sandbox' => env('PURCHASES_APPLE_SANDBOX_URL', 'https://sandbox.itunes.apple.com'),
            ],
            'password' => env('PURCHASES_APPLE_PASSWORD'),
            'certificate_clock_skew' => env('PURCHASES_APPLE_CERTIFICATE_CLOCK_SKEW', 60),
            'api' => [
                'key_id' => env('PURCHASES_APPLE_KEY_ID'),
                'issuer_id' => env('PURCHASES_APPLE_ISSUER_ID'),
                'private_key' => env('PURCHASES_APPLE_PRIVATE_KEY'),
                'url' => [
                    'live' => env('PURCHASES_APPLE_API_LIVE_URL', 'https://api.storekit.itunes.apple.com'),
                    'sandbox' => env('PURCHASES_APPLE_API_SANDBOX_URL', 'https://api.storekit-sandbox.itunes.apple.com'),
                ],
            ],
        ],

        'google' => [
            'package_name' => env('PURCHASES_GOOGLE_PACKAGE_NAME'),
            'service_account' => [
                'client_email' => env('PURCHASES_GOOGLE_CLIENT_EMAIL'),
                'private_key' => env('PURCHASES_GOOGLE_PRIVATE_KEY'),
                'token_uri' => env('PURCHASES_GOOGLE_TOKEN_URI', 'https://oauth2.googleapis.com/token'),
            ],
            'base_url' => env('PURCHASES_GOOGLE_BASE_URL', 'https://androidpublisher.googleapis.com'),
            'acknowledge' => env('PURCHASES_GOOGLE_ACKNOWLEDGE', true),

            // Pub/Sub pushes are authenticated before they are read — fail-closed.
            'push' => [
                'authenticate' => env('PURCHASES_GOOGLE_PUSH_AUTHENTICATE', true),
                'audience' => env('PURCHASES_GOOGLE_PUSH_AUDIENCE'),
                'service_account_email' => env('PURCHASES_GOOGLE_PUSH_SERVICE_ACCOUNT'),
                'token' => env('PURCHASES_GOOGLE_PUSH_TOKEN'),
                'jwks_url' => env('PURCHASES_GOOGLE_PUSH_JWKS_URL', 'https://www.googleapis.com/oauth2/v3/certs'),
                'jwks_cache_ttl' => env('PURCHASES_GOOGLE_PUSH_JWKS_CACHE_TTL', 3600),
            ],
        ],

        'stripe' => [
            'secret' => env('PURCHASES_STRIPE_SECRET'),
            'webhook_secret' => env('PURCHASES_STRIPE_WEBHOOK_SECRET'),
            'api_version' => env('PURCHASES_STRIPE_API_VERSION', '2026-05-27.dahlia'),
            'base_url' => env('PURCHASES_STRIPE_BASE_URL', 'https://api.stripe.com/v1'),
            'tolerance' => env('PURCHASES_STRIPE_TOLERANCE', 300),
        ],
    ],
];

Kľúče balíka

KľúčPredvolenéÚčel
models.*modely balíkaEloquent model pre každý typ záznamu — nahraďte ho vlastnou podtriedou; iná trieda vyhodí výnimku.
providersApple, Google, StripeRegistrované triedy poskytovateľov, vyhľadávané podľa id(). Musí to byť zoznam tried implementujúcich Provider.
key_typebigintTyp kľúča polymorfného vlastníka: bigint, uuid alebo ulid; čokoľvek iné vyhodí výnimku pri spustení migrácií.
audit.enabledtrueZapisovať každý overený payload do purchase_notifications.
queue.enabledfalseOveriť synchrónne, uložiť cez frontu.
queue.connectionnullSpojenie fronty pre asynchrónne ukladanie; nenastavené alebo prázdne = predvolené spojenie.
queue.queuenullNázov fronty pre asynchrónne ukladanie; nenastavené alebo prázdne = predvolená fronta.
routes.enabledfalseZaregistrovať pribalenú webhook routu.
routes.prefixpurchasesURI prefix webhook routy.
routes.middleware['api']Middleware webhook routy — zoznam názvov.

Apple — settings.apple

KľúčEnvPredvolené
bundle_idPURCHASES_APPLE_BUNDLE_ID—
app_apple_idPURCHASES_APPLE_APP_APPLE_ID—
sandboxPURCHASES_APPLE_SANDBOXfalse
url.livePURCHASES_APPLE_LIVE_URLbuy.itunes.apple.com
url.sandboxPURCHASES_APPLE_SANDBOX_URLsandbox.itunes.apple.com
passwordPURCHASES_APPLE_PASSWORD—
certificate_clock_skewPURCHASES_APPLE_CERTIFICATE_CLOCK_SKEW60
api.key_idPURCHASES_APPLE_KEY_ID—
api.issuer_idPURCHASES_APPLE_ISSUER_ID—
api.private_keyPURCHASES_APPLE_PRIVATE_KEY—
api.url.livePURCHASES_APPLE_API_LIVE_URLapi.storekit.itunes.apple.com
api.url.sandboxPURCHASES_APPLE_API_SANDBOX_URLapi.storekit-sandbox.itunes.apple.com

bundle_id je pre Apple povinné: každá notifikácia App Store — aj každá transakcia, ktorú vráti App Store Server API — ho musí uvádzať, inak sa odmietne; zároveň ním balík podpisuje požiadavky na App Store Server API. app_apple_id (App Store Connect → App Information) je povinné v produkcii, kde ho notifikácia musí niesť. sandbox je predvolene false — produkcia; na true ho nastavte len na serveri, ktorý prijíma notifikácie zo Sandboxu, čím sa aj verifyReceipt a App Store Server API prepnú na sandbox adresy. api.* zapína App Store Server API, modernú náhradu za verifyReceipt; password je zdieľaný kľúč pre staršie účtenky. certificate_clock_skew je tolerancia v sekundách (0–3600) na oboch koncoch obdobia platnosti každého certifikátu — hodnota mimo rozsahu vyhodí InvalidConfigurationException, takže preklep kontrolu nikdy nevypne, kým prázdna hodnota sa považuje za nenastavenú a platí 60.

Google — settings.google

KľúčEnvPredvolené
package_namePURCHASES_GOOGLE_PACKAGE_NAME—
service_account.client_emailPURCHASES_GOOGLE_CLIENT_EMAIL—
service_account.private_keyPURCHASES_GOOGLE_PRIVATE_KEY—
service_account.token_uriPURCHASES_GOOGLE_TOKEN_URIoauth2.googleapis.com/token
base_urlPURCHASES_GOOGLE_BASE_URLandroidpublisher.googleapis.com
acknowledgePURCHASES_GOOGLE_ACKNOWLEDGEtrue
push.authenticatePURCHASES_GOOGLE_PUSH_AUTHENTICATEtrue
push.audiencePURCHASES_GOOGLE_PUSH_AUDIENCE—
push.service_account_emailPURCHASES_GOOGLE_PUSH_SERVICE_ACCOUNT—
push.tokenPURCHASES_GOOGLE_PUSH_TOKEN—
push.jwks_urlPURCHASES_GOOGLE_PUSH_JWKS_URLwww.googleapis.com/oauth2/v3/certs
push.jwks_cache_ttlPURCHASES_GOOGLE_PUSH_JWKS_CACHE_TTL3600

acknowledge určuje, či sa overené nákupy v Google Play automaticky potvrdia (acknowledge). push.* autentifikuje real-time developer notifikácie a bez konfigurácie ich odmieta — pozrite Google Play. push.jwks_cache_ttl, doba uloženia podpisových kľúčov Google v cache v sekundách, musí byť najmenej 1.

Stripe — settings.stripe

KľúčEnvPredvolené
secretPURCHASES_STRIPE_SECRET—
webhook_secretPURCHASES_STRIPE_WEBHOOK_SECRET—
api_versionPURCHASES_STRIPE_API_VERSION2026-05-27.dahlia
base_urlPURCHASES_STRIPE_BASE_URLapi.stripe.com/v1
tolerancePURCHASES_STRIPE_TOLERANCE300

tolerance je tolerancia časovej pečiatky webhooku v sekundách (najmenej 1, predvolene 300), takže ochranu proti replayu preklep nikdy nevypne; api_version sa posiela v hlavičke Stripe-Version pri každom REST volaní. secret je potrebný na čítanie cez REST vrátane kontroly faktúry pri každej udalosti payment_intent.* v aktuálnych verziách API (pozrite Stripe).

Prostredie (env)

Všetky prístupové údaje sa riadia cez env, takže konfiguráciu publikujete len zriedka. Konfiguračný súbor odovzdáva hodnoty z env bez úprav a balík ich číta striktne. Prepínače zapnuté/vypnuté — PURCHASES_AUDIT_ENABLED, PURCHASES_QUEUE_ENABLED, PURCHASES_ROUTES_ENABLED, PURCHASES_APPLE_SANDBOX, PURCHASES_GOOGLE_ACKNOWLEDGE a PURCHASES_GOOGLE_PUSH_AUTHENTICATE — prijímajú true/false, 1/0, on/off alebo yes/no; nenastavený alebo prázdny prepínač (KEY=) si ponechá zdokumentovanú predvolenú hodnotu (pri autentifikácii pushov je to zapnuté — bezpečne odmietajúci stav). Čokoľvek iné, napríklad PURCHASES_KEY_TYPE mimo bigint, uuid a ulid, vyhodí InvalidConfigurationException s názvom kľúča — preklep sa nikdy potichu nezmení na predvolenú hodnotu:

# Apple — your app, App Store Server API (+ legacy verifyReceipt shared secret)
PURCHASES_APPLE_BUNDLE_ID=com.example.app
PURCHASES_APPLE_APP_APPLE_ID=1234567890
PURCHASES_APPLE_SANDBOX=false
PURCHASES_APPLE_KEY_ID=
PURCHASES_APPLE_ISSUER_ID=
PURCHASES_APPLE_PRIVATE_KEY=
PURCHASES_APPLE_PASSWORD=
PURCHASES_APPLE_CERTIFICATE_CLOCK_SKEW=60

# Google Play — service account
PURCHASES_GOOGLE_PACKAGE_NAME=
PURCHASES_GOOGLE_CLIENT_EMAIL=
PURCHASES_GOOGLE_PRIVATE_KEY=
PURCHASES_GOOGLE_ACKNOWLEDGE=true
PURCHASES_GOOGLE_PUSH_AUDIENCE=https://your-app.test/purchases/webhooks/google
PURCHASES_GOOGLE_PUSH_SERVICE_ACCOUNT=[email protected]

# Stripe
PURCHASES_STRIPE_SECRET=
PURCHASES_STRIPE_WEBHOOK_SECRET=
PURCHASES_STRIPE_TOLERANCE=300

# Package behaviour
PURCHASES_KEY_TYPE=bigint
PURCHASES_AUDIT_ENABLED=true
PURCHASES_QUEUE_ENABLED=false
PURCHASES_ROUTES_ENABLED=false
PURCHASES_ROUTES_PREFIX=purchases

Striktné nastavenia

Rovnako striktné sú aj ostatné nastavenia. Premenná, ktorá nie je nastavená — chýba alebo je prázdna, napríklad PURCHASES_STRIPE_TOLERANCE= —, dostane predvolenú hodnotu; premenná nastavená v nesprávnom tvare vyhodí RoundlyConsulting\Purchases\Exceptions\InvalidConfigurationException s názvom kľúča:

  • Trvania — PURCHASES_STRIPE_TOLERANCE, PURCHASES_GOOGLE_PUSH_JWKS_CACHE_TTL a PURCHASES_APPLE_CERTIFICATE_CLOCK_SKEW — prijímajú celé číslo, napríklad 300; five či 300.5 vyhodia výnimku namiesto toho, aby sa z nich stala 0.
  • URL adresy, verzia API, prefix routy a spojenie aj názov fronty musia byť reťazce. Pre predvolené spojenie a frontu nechajte premenné fronty nenastavené alebo prázdne.
  • purchases.providers a purchases.routes.middleware musia byť zoznamy a každý poskytovateľ musí implementovať RoundlyConsulting\Purchases\Providers\Provider.
  • Prázdny prístupový údaj (PURCHASES_GOOGLE_PUSH_TOKEN=) sa považuje za nenastavený, takže sa číta ako nenakonfigurovaný; údaj, ktorý nie je reťazec, vyhodí výnimku.

Tajné kľúče poskytovateľov sa čítajú len z konfigurácie a env, sú označené #[SensitiveParameter], takže sa nikdy neobjavia v stack trace, a nikdy sa nelogujú. php artisan about ich zobrazí len ako SET alebo MISSING a chybné trvanie či zoznam poskytovateľov ako INVALID.

Prejavte lásku k open source

Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.

Ďalšie spôsoby podpory vrátane kryptomien

Odoslaním daru súhlasíte s našimi podmienkami prijímania darov.

Chcete to zabudovať do svojho produktu?

Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.