Coder Social home page Coder Social logo

protonemedia / laravel-paddle Goto Github PK

View Code? Open in Web Editor NEW
195.0 10.0 18.0 114 KB

Paddle.com API integration for Laravel with support for webhooks/events

Home Page: https://protone.media/en/blog/a-new-laravel-package-to-handle-payments-and-subscriptions-with-paddle

License: MIT License

PHP 99.33% Blade 0.67%
laravel-paddle laravel laravel-package payment payments payment-gateway payment-integration paddle

laravel-paddle's Introduction

⚠️ I'm unsure about the future of this package. I might be abandoning it, so please consider using Laravel Cashier (Paddle).

Laravel Paddle

Latest Version on Packagist run-tests Quality Score Total Downloads

This package provides an integration with Paddle.com for Laravel. Read the blogpost about the introduction of the package!

Features

Sponsor this package!

❤️ We proudly support the community by developing Laravel packages and giving them away for free. If this package saves you time or if you're relying on it professionally, please consider sponsoring the maintenance and development. Keeping track of issues and pull requests takes time, but we're happy to help!

Installation

Only the master branch and version 2.0 of this package are compatible with Laravel 8.0 and higher. If you're still using an older version of Laravel (or PHP < 7.3), please use the chart below to find out which version you should use. Mind that older versions are no longer supported.

Laravel Version Package Version
8.0-11.0 2.0
6.0-7.0 1.0

You can install the package via composer:

composer require protonemedia/laravel-paddle

Configuration

Publish the config file:

php artisan vendor:publish --provider="ProtoneMedia\LaravelPaddle\PaddleServiceProvider" --tag=config

Set your Vendor ID and Code and the Public Key settings in your .env file or in the config/paddle.php file. The Public Key is used to verify incoming webhooks from Paddle.

PADDLE_SANDBOX=false
PADDLE_VENDOR_ID=123
PADDLE_VENDOR_AUTH_CODE=456
PADDLE_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----"

Paddle Sandbox

As of version 2.2.0, this package supports the Paddle Sandbox environment. To use this environment, set the sandbox_environment configuration key to true. This will configure the API URLs, as well as the Paddle JavaScript library. If you've published the Blade View while using a previous version of this package, make sure you republish the view:

php artisan vendor:publish --provider="ProtoneMedia\LaravelPaddle\PaddleServiceProvider" --tag=views

Usage

The API calls are available with the Paddle facade. Check out the the documentation to learn all about the Paddle API. You can build your API calls fluently or you could simply pass an array which holds the data. This package has some basic validation rules for the given data and this might result in an InvalidDataException if your data is invalid. Whenever an API call fails it will throw a PaddleApiException.

// Fluent:
$paddleResponse = Paddle::product()
    ->generatePayLink()
    ->productId($paddlePlanId)
    ->customerEmail($team->owner->email)
    ->passthrough(['team_id' => $team->id])
    ->send();

// Array with payload:
$payload = [
    'product_id' => $paddlePlanId,
    'customer_email' => $team->owner->email,
    'passthrough' => ['team_id' => $team->id],
];

$paddleResponse = Paddle::product()
    ->generatePayLink($payload)
    ->send();

return Redirect::to($paddleResponse['url']);

Available API calls

// alerts
Paddle::alert()->getWebhookHistory();

// checkouts
Paddle::checkout()->getOrderDetails();
Paddle::checkout()->getUserHistory();
Paddle::checkout()->getPrices();

// products
Paddle::product()->listCoupons();
Paddle::product()->createCoupon();
Paddle::product()->updateCoupon();
Paddle::product()->deleteCoupon();

Paddle::product()->listProducts();
Paddle::product()->generateLicense();
Paddle::product()->generatePayLink();
Paddle::product()->listTransactions($entity, $id);

// subscriptions
Paddle::subscription()->listPlans();
Paddle::subscription()->createPlan();

Paddle::subscription()->listUsers();
Paddle::subscription()->updateUser();
Paddle::subscription()->previewUpdate();
Paddle::subscription()->cancelUser();

Paddle::subscription()->listModifiers();
Paddle::subscription()->createModifier();
Paddle::subscription()->deleteModifier();

Paddle::subscription()->listPayments();
Paddle::subscription()->reschedulePayment();
Paddle::subscription()->createOneOffCharge($subscriptionId);

Webhooks and Laravel Events

You can configure your webhook URI in the paddle.php config file. Update your webhook settings at Paddle accordingly. By default the URI is paddle/webhook. This means that the webhook calls will be posted to https://your-domain.com/paddle/webhook.

Every webhook will be mapped to an Event and contains the payload of the webhook. For example when the Subscription Created webhook is called, the request is verified and a SubscriptionCreated event will be fired.

Events:

  • ProtoneMedia\LaravelPaddle\Events\HighRiskTransactionCreated
  • ProtoneMedia\LaravelPaddle\Events\HighRiskTransactionUpdated
  • ProtoneMedia\LaravelPaddle\Events\LockerProcessed
  • ProtoneMedia\LaravelPaddle\Events\NewAudienceMember
  • ProtoneMedia\LaravelPaddle\Events\PaymentDisputeClosed
  • ProtoneMedia\LaravelPaddle\Events\PaymentDisputeCreated
  • ProtoneMedia\LaravelPaddle\Events\PaymentRefunded
  • ProtoneMedia\LaravelPaddle\Events\PaymentSucceeded
  • ProtoneMedia\LaravelPaddle\Events\SubscriptionCancelled
  • ProtoneMedia\LaravelPaddle\Events\SubscriptionCreated
  • ProtoneMedia\LaravelPaddle\Events\SubscriptionPaymentFailed
  • ProtoneMedia\LaravelPaddle\Events\SubscriptionPaymentRefunded
  • ProtoneMedia\LaravelPaddle\Events\SubscriptionPaymentSucceeded
  • ProtoneMedia\LaravelPaddle\Events\SubscriptionUpdated
  • ProtoneMedia\LaravelPaddle\Events\TransferCreated
  • ProtoneMedia\LaravelPaddle\Events\TransferPaid
  • ProtoneMedia\LaravelPaddle\Events\UpdateAudienceMember

Some webhooks, like the Fulfillment Webhook, don't have an alert_name key. Those webhooks will be mapped to a ProtoneMedia\LaravelPaddle\Events\GenericWebhook event.

When you register a listener to handle the event, the payload is easily accessible. You also have access to the original HTTP request.

<?php

namespace App\Listeners;

use ProtoneMedia\LaravelPaddle\Events\SubscriptionCreated;

class CreateSubscriptionModel
{
    public function handle(SubscriptionCreated $event)
    {
        $status = $event->status;

        $nextBillDate = $event->next_bill_date;

        // or

        $webhookData = $event->all();

        //

        $request = $event->getRequest();
    }
}

Blade directive

This directive imports the Paddle JavaScript library and configures it with your Vendor ID.

<body>
    {{-- your app --}}

    @paddle
</body>

Testing

composer test

Changelog

Please see CHANGELOG for more information what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Other Laravel packages

  • Laravel Blade On Demand: Laravel package to compile Blade templates in memory.
  • Laravel Cross Eloquent Search: Laravel package to search through multiple Eloquent models.
  • Laravel Eloquent Scope as Select: Stop duplicating your Eloquent query scopes and constraints in PHP. This package lets you re-use your query scopes and constraints by adding them as a subquery.
  • Laravel FFMpeg: This package provides an integration with FFmpeg for Laravel. The storage of the files is handled by Laravel's Filesystem.
  • Laravel MinIO Testing Tools: Run your tests against a MinIO S3 server.
  • Laravel Mixins: A collection of Laravel goodies.
  • Laravel Task Runner: Write Shell scripts like Blade Components and run them locally or on a remote server.
  • Laravel Verify New Email: This package adds support for verifying new email addresses: when a user updates its email address, it won't replace the old one until the new one is verified.
  • Laravel XSS Protection: Laravel Middleware to protect your app against Cross-site scripting (XSS). It sanitizes request input, and it can sanatize Blade echo statements.

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.

laravel-paddle's People

Contributors

laravel-shift avatar pascalbaljet avatar sandulat avatar sergunik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laravel-paddle's Issues

"Undefined index: error" when calling getOrderDetails

Whenever I call Paddle::checkout()->getOrderDetails I get this error, I think it is related to a check for a "success" field in the Request class, the response of getOrderDetails does not include this field.

if ($json['success'] ?? null) {
   return $json['response'];
}

Line 116-118 in protonemedia/laravel-paddle/src/Api/Request.php

Authentication/Permission Error

Hello!

I'm not sure is it a bug or my mistake.

Let me explain my current situation:

  • Imported laravel-paddle package via composer into my Laravel 5.8 project.
  • Defined my credentials into my environment file.
  • Created my paddle account and also created a product/subscription.

And my code side:

$payload = [
        'product_id' => $paddlePlanId,
        'customer_email' => $user->email,
        'passthrough' => ['team_id' => $user->id],
];
    $paddleResponse = Paddle::product()
        ->generatePayLink($payload)
        ->send();`

What I'm getting:

ProtoneMedia \ LaravelPaddle \ Api \ PaddleApiException
[107] You don't have permission to access this resource

What is the problem? I guess it is an authentication issue. Because I can not list my products too. Am I missing something?

SSLv3 error on webhook for Paddle

Hi,

On a Laravel forge spinned up server I am trying to use the package but I get this error:
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure

This is with the Webhook Simulator tester.

Any ideas how to get it to work?

Live mode problem

This paddle package working fine for sandbox. But, if I change to PADDLE_SANDBOX=false and give my exact Paddle credentials for the production server, then it redirect me to this link: https://buy.paddle.com/checkout/error. Why does it happening?

paddle billing support

I am new to paddle.
And I have a billing account instead of the classic one.

Is this package compatible with the latest paddle account type?

Thanks in advance!

Getting passthrough value

The passthrough variable is decoded to an array if I'm correct, however getting its value doesn't seem to be working. Is it correct that I should use $team_id = $event->passthrough['team_id'] in a Listener?

Also: the Paddle docs state that a HTTP 200 code should be returned when a webhook is received (else they'll keep pinging it every 15 minutes for 3 days). So at the end of my Listener I should add return response()->json(['status' => 'OK']);?

I'm relatively new to this, and others might be as well, so if this is useful for you I'm happy to create a pull request when I'm done implementing with some suggestions for the README with some additional details like ones above.

Return HTTP response

At the moment the only way to not return a HTTP 200 code is by throwing an Exception and exposing a stacktrace to the requester, which I am not a fan of.

But not returning a HTTP 200 code is essential when you want Paddles event system to fire an event again at a later point, for example when you need the subscription_created data before you can handle the subscription_payment_succeeded request.

Is there any other option? At the moment I don't see an option because WebhookController doesn't responds to the request.

Edit: https://laravel.com/docs/9.x/errors#renderable-exceptions that's the solution.

Support .env variables according read.me

Hello!
I'm using v2.4.0 and according to documentation I could set the vendor_id, vendor_auth_code and public_key on .env or in published config file. But I've set in .env and my Paddle::subscription()->listPlans() returned a non permission returned from Paddle ([107] You don't have permission to access this resource). So I investigated and found on the src/Api/Request.php line 101 the code:

$data = $this->getData() + ['vendor_id' => config('paddle.vendor_id')];

if ($method === static::METHOD_POST) {
    $data['vendor_auth_code'] = config('paddle.vendor_auth_code');
}

This mean that the vendor_id and vendor_auth_code is coming only from config file and it's not getting from .env, right?

I solved it adding a null coalescing operator in this part and I would like to check if can I send a PR with this new code?

$data = $this->getData() + ['vendor_id' => config('paddle.vendor_id')??env('PADDLE_VENDOR_ID')];

if ($method === static::METHOD_POST) {
    $data['vendor_auth_code'] = config('paddle.vendor_auth_code')??env('PADDLE_VENDOR_AUTH_CODE');
}

I've changed all other config usages too for try to use the .env if config variable is not set.
Thanks!

Paddle's Product Fulfillment webhook will return a 500 Error because there's no 'alert_name'

If you select webhook as a fulfillment for a product on Paddle, this will be used: https://developer.paddle.com/webhook-reference/product-fulfillment/fulfillment-webhook

As there is no "alert_name" set with this webhook, the library will have a 500 error. This is where the code breaks:

Event.php:

public static function fire(array $data)
    {
        $event = Str::studly($data['alert_name']);

        $eventClass = __NAMESPACE__ . '\\' . $event;

        event(new $eventClass($data));
    }

Getting error in webhook call.

Thanks a lot for the amazing package.

While making a webhook call from the Paddle webhook simulator, I am getting below error.

error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure

I configure the server with Laravel Forge.

Is there any steps I missing regarding the configuration.

SSL issue

I'm quite lost regarding where exactly this issue occurs, so please excuse me if it turns out that it has nothing to do with this package.

When I test my webhook in the Paddle dashboard, I get error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure. First, I thought that Paddle was connecting over SSLv3 but that seems highly unlikely as I've done some searching and it seems this is ancient and not recommended encryption.

On my nginx server I have (this might be relevant to the issue):

ssl_protocols TLSv1.2;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/dhparams.pem;

The reason that I'm posting this issue here is that WebhookController has

$verified = openssl_verify(
  serialize($data),
  base64_decode($encodedSignature),
  openssl_get_publickey(config('paddle.public_key')),
  OPENSSL_ALGO_SHA1
);

Judging from the response that I get in the Paddle dashboard I still think it's on their end but I wanted to double check if the issue could come from the code above, or that maybe you ran into this issue as well while working on this package.

I have set my public_key in my ENV file and run config:cache on deployment.

installation error on new laravel

I'm trying to install the package on the new laravel version but I get an error because of the package requirement
new laravel using egulias/email-validator 4.1
but this package requires egulias/email-validator 2.1 or 3.1

Sandbox

Can I use paddle sandbox in version 1 of this package?
I am using Laravel 7.

getPrices returns "Bad Method Call"

Hi there,

First, thanks for this amazing package.

I am trying to get the price for my product with the following code:

Paddle::checkout()
                 ->getPrices(['product_ids' => '594915', 'customer_ip' => '213.55.224.117'])
                 ->send()

But unfortunately, it returns a "Bad Method Call", like below:

image

Can I ask your help to clarify what am I doing wrong?

Thanks in advance,
Bruno

[139] The given prices format is not valid.

I got this error.

ProtoneMedia\LaravelPaddle\Api\PaddleApiException
[139] The given prices format is not valid. The prices must have the format of ['currency:amount', 'currency:amount', …]. 

Here is my code:

        $products = "1,2,3";
        $user = Auth::user();
        
        $checkOutUrl = Paddle::product()->generatePayLink([
            'title' => '3D Wallpaper',
            'webhook_url' => 'http://05c0-118-179-103-52.ngrok.io/paddle/webhook',
            'prices' => '[USD:19.99]',
            'customer_email' => $user->email,
            'customer_country' => 'BD',
            'passthrough' => ['products' => $products],
        ])->send()['url'];

How to solve this?

Multi vendor support?

At the moment, this library can be user for one vendor. What if our app has multiple tenants, and for each one of them we want to allow payments?

That would be possible if Request would not overwrite the vendor id and vendor_auth_code. and just read them from the config if the values do not exist in the $data.

If you would support PR for this, I can do that.

Undefined index: alert_name

Hello! Thank you for building this awesome package!

When I receive a "payment_succeeded" webhook from Paddle, an exception log is created:

[2020-01-27 22:58:09] production.ERROR: Undefined index: alert_name {"exception":"[object] (ErrorException(code: 0): Undefined index: alert_name at .../vendor/protonemedia/laravel-paddle/src/Events/Event.php:59)

However, everything works excellently. My listener catches the event and does the business logic as expected. I don't understand why this exception is happening while everything works as expected. It feels like Paddle is dispatching 2 requests, instead of 1. But the Alert History from Paddle shows only 1 request, and the payload does contain alert_name.

Should I submit a PR which checks if "alert_name" exists in the payload, inside the fire method from the Event base class? Like this:

    public static function fire(array $data)
    {
        if (isset($data['alert_name'])) {
            $event = Str::studly($data['alert_name']);

            $eventClass = __NAMESPACE__ . '\\' . $event;

            event(new $eventClass($data));
        }
    }

Thank you very much!

Package installation problem

I'm using laravel 7 and php 8.0. When I'm trying to install this package, I got this error:

Problem 1 - Root composer.json requires protonemedia/laravel-paddle ^2.3 -> satisfiable by protonemedia/laravel-paddle[v2.3.0]. - protonemedia/laravel-paddle v2.3.0 requires illuminate/support ^8.67 -> found illuminate/support[v8.67.0, ..., 8.x-dev] but these were not loaded, likely because it conflicts with another require.

and when I'm trying to install 1.0v of this package, I got this error:

[InvalidArgumentException] Package protonemedia/laravel-paddle at version ^1 has a PHP requirement incompatible with your PHP version, PHP ext ensions and Composer version: - protonemedia/laravel-paddle 1.2.1 requires php ^7.2 which does not match your installed version 8.0.10

It would be better If I can install the latest version of this package. Please help me to solve this.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.