laravel / cashier-paddle

Cashier Paddle provides an expressive, fluent interface to Paddle's subscription billing services.
https://laravel.com/docs/cashier-paddle
MIT License
238 stars 57 forks source link

Activate subscription is not working. #258

Closed livan2r closed 3 months ago

livan2r commented 4 months ago

Cashier Paddle Version

2.4.2

Laravel Version

10.48.10

PHP Version

8.2.12

Database Driver & Version

No response

Description

$subscription->activate(); to force a trial to end immediately and activate the subscription is failing to me on https://sandbox-api.paddle.com the API response returns the error message Paddle API error 'Invalid request' occurred.

I was digging a little bit and it looks like the issue is related to the content type that the Paddle API is expecting from this endpoint. For example, by calling the asForm method before making the request in Cashier:api() the response is successful.

Steps To Reproduce

On a trial subscription call $subscription->activate();

driesvints commented 4 months ago

That would seem weird to me as it's just a POST request: https://developer.paddle.com/api-reference/subscriptions/activate-subscription. Is there any other info about the failing request? Any other info in the message body from the return response or in the headers?

livan2r commented 4 months ago

Hi, @driesvints. Yeah, it looks weird to me too because it's a very simple endpoint. I'm sharing with you the response that I'm getting with the current Cashier::api method (asJson, default content-type), but if I send the request asForm the response is successful, maybe something changed on Padde's sandbox API for this endpoint.

\Illuminate\Http\Client\Response::__set_state(array(
   'response' => 
  \GuzzleHttp\Psr7\Response::__set_state(array(
     'reasonPhrase' => 'Bad Request',
     'statusCode' => 400,
     'headers' => 
    array (
      'Date' => 
      array (
        0 => 'Fri, 10 May 2024 16:39:00 GMT',
      ),
      'Content-Type' => 
      array (
        0 => 'application/json',
      ),
      'Content-Length' => 
      array (
        0 => '273',
      ),
      'Connection' => 
      array (
        0 => 'keep-alive',
      ),
      'Cache-Control' => 
      array (
        0 => 'no-store, max-age=0',
      ),
      'content-security-policy' => 
      array (
        0 => 'default-src \'none\'; frame-ancestors \'none\'; base-uri \'none\'',
      ),
      'cross-origin-embedder-policy' => 
      array (
        0 => 'require-corp',
      ),
      'cross-origin-opener-policy' => 
      array (
        0 => 'same-origin',
      ),
      'cross-origin-resource-policy' => 
      array (
        0 => 'same-site',
      ),
      'permissions-policy' => 
      array (
        0 => 'accelerometer=(),ambient-light-sensor=(),autoplay=(),battery=(),camera=(),display-capture=(),document-domain=(),encrypted-media=(),fullscreen=(),gamepad=(),geolocation=(),gyroscope=(),layout-animations=(self),legacy-image-formats=(self),magnetometer=(),microphone=(),midi=(),oversized-images=(self),payment=(),picture-in-picture=(),publickey-credentials-get=(),screen-wake-lock=(),speaker-selection=(),sync-xhr=(self),unoptimized-images=(self),unsized-media=(self),usb=(),web-share=(),xr-spatial-tracking=()',
      ),
      'pragma' => 
      array (
        0 => 'no-cache',
      ),
      'referrer-policy' => 
      array (
        0 => 'no-referrer',
      ),
      'request-id' => 
      array (
        0 => 'b3e38702-d804-4f30-a163-3b6feca5c4d0',
      ),
      'strict-transport-security' => 
      array (
        0 => 'max-age=31536000; includeSubDomains; preload',
      ),
      'x-content-type-options' => 
      array (
        0 => 'nosniff',
      ),
      'x-frame-options' => 
      array (
        0 => 'deny',
      ),
      'x-permitted-cross-domain-policies' => 
      array (
        0 => 'none',
      ),
      'x-robots-tag' => 
      array (
        0 => 'noindex, nofollow',
      ),
      'CF-Cache-Status' => 
      array (
        0 => 'DYNAMIC',
      ),
      'Server' => 
      array (
        0 => 'cloudflare',
      ),
      'CF-RAY' => 
      array (
        0 => '881b5ce58bf2a66f-MIA',
      ),
    ),
     'headerNames' => 
    array (
      'date' => 'Date',
      'content-type' => 'Content-Type',
      'content-length' => 'Content-Length',
      'connection' => 'Connection',
      'cache-control' => 'Cache-Control',
      'content-security-policy' => 'content-security-policy',
      'cross-origin-embedder-policy' => 'cross-origin-embedder-policy',
      'cross-origin-opener-policy' => 'cross-origin-opener-policy',
      'cross-origin-resource-policy' => 'cross-origin-resource-policy',
      'permissions-policy' => 'permissions-policy',
      'pragma' => 'pragma',
      'referrer-policy' => 'referrer-policy',
      'request-id' => 'request-id',
      'strict-transport-security' => 'strict-transport-security',
      'x-content-type-options' => 'x-content-type-options',
      'x-frame-options' => 'x-frame-options',
      'x-permitted-cross-domain-policies' => 'x-permitted-cross-domain-policies',
      'x-robots-tag' => 'x-robots-tag',
      'cf-cache-status' => 'CF-Cache-Status',
      'server' => 'Server',
      'cf-ray' => 'CF-RAY',
    ),
     'protocol' => '1.1',
     'stream' => 
    \GuzzleHttp\Psr7\Stream::__set_state(array(
       'stream' => NULL,
       'size' => NULL,
       'seekable' => true,
       'readable' => true,
       'writable' => true,
       'uri' => 'php://temp',
       'customMetadata' => 
      array (
      ),
    )),
  )),
   'decoded' => 
  array (
    'error' => 
    array (
      'type' => 'request_error',
      'code' => 'bad_request',
      'detail' => 'Invalid request',
      'documentation_url' => 'https://developer.paddle.com/v1/errors/shared/bad_request',
      'errors' => 
      array (
        0 => 
        array (
          'field' => '',
          'message' => 'invalid input',
        ),
      ),
    ),
    'meta' => 
    array (
      'request_id' => 'b3e38702-d804-4f30-a163-3b6feca5c4d0',
    ),
  ),
   'cookies' => 
  \GuzzleHttp\Cookie\CookieJar::__set_state(array(
     'cookies' => 
    array (
    ),
     'strictMode' => false,
  )),
   'transferStats' => 
  \GuzzleHttp\TransferStats::__set_state(array(
     'request' => 
    \GuzzleHttp\Psr7\Request::__set_state(array(
       'method' => 'POST',
       'requestTarget' => NULL,
       'uri' => 
      \GuzzleHttp\Psr7\Uri::__set_state(array(
         'scheme' => 'https',
         'userInfo' => '',
         'host' => 'sandbox-api.paddle.com',
         'port' => NULL,
         'path' => '/subscriptions/sub_01hxhnxneeggtwvqthyrv6s2c9/activate',
         'query' => '',
         'fragment' => '',
         'composedComponents' => 'https://sandbox-api.paddle.com/subscriptions/sub_01hxhnxneeggtwvqthyrv6s2c9/activate',
      )),
       'headers' => 
      array (
        'Content-Length' => 
        array (
          0 => '2',
        ),
        'Content-Type' => 
        array (
          0 => 'application/json',
        ),
        'Host' => 
        array (
          0 => 'sandbox-api.paddle.com',
        ),
        'Authorization' => 
        array (
          0 => 'Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
        ),
        'User-Agent' => 
        array (
          0 => 'Laravel\\Paddle/2.4.2',
        ),
        'Paddle-Version' => 
        array (
          0 => '1',
        ),
      ),
       'headerNames' => 
      array (
        'content-length' => 'Content-Length',
        'content-type' => 'Content-Type',
        'host' => 'Host',
        'authorization' => 'Authorization',
        'user-agent' => 'User-Agent',
        'paddle-version' => 'Paddle-Version',
      ),
       'protocol' => '1.1',
       'stream' => 
      \GuzzleHttp\Psr7\Stream::__set_state(array(
         'stream' => NULL,
         'size' => 2,
         'seekable' => true,
         'readable' => true,
         'writable' => true,
         'uri' => 'php://temp',
         'customMetadata' => 
        array (
        ),
      )),
    )),
     'response' => 
    \GuzzleHttp\Psr7\Response::__set_state(array(
       'reasonPhrase' => 'Bad Request',
       'statusCode' => 400,
       'headers' => 
      array (
        'Date' => 
        array (
          0 => 'Fri, 10 May 2024 16:39:00 GMT',
        ),
        'Content-Type' => 
        array (
          0 => 'application/json',
        ),
        'Content-Length' => 
        array (
          0 => '273',
        ),
        'Connection' => 
        array (
          0 => 'keep-alive',
        ),
        'Cache-Control' => 
        array (
          0 => 'no-store, max-age=0',
        ),
        'content-security-policy' => 
        array (
          0 => 'default-src \'none\'; frame-ancestors \'none\'; base-uri \'none\'',
        ),
        'cross-origin-embedder-policy' => 
        array (
          0 => 'require-corp',
        ),
        'cross-origin-opener-policy' => 
        array (
          0 => 'same-origin',
        ),
        'cross-origin-resource-policy' => 
        array (
          0 => 'same-site',
        ),
        'permissions-policy' => 
        array (
          0 => 'accelerometer=(),ambient-light-sensor=(),autoplay=(),battery=(),camera=(),display-capture=(),document-domain=(),encrypted-media=(),fullscreen=(),gamepad=(),geolocation=(),gyroscope=(),layout-animations=(self),legacy-image-formats=(self),magnetometer=(),microphone=(),midi=(),oversized-images=(self),payment=(),picture-in-picture=(),publickey-credentials-get=(),screen-wake-lock=(),speaker-selection=(),sync-xhr=(self),unoptimized-images=(self),unsized-media=(self),usb=(),web-share=(),xr-spatial-tracking=()',
        ),
        'pragma' => 
        array (
          0 => 'no-cache',
        ),
        'referrer-policy' => 
        array (
          0 => 'no-referrer',
        ),
        'request-id' => 
        array (
          0 => 'b3e38702-d804-4f30-a163-3b6feca5c4d0',
        ),
        'strict-transport-security' => 
        array (
          0 => 'max-age=31536000; includeSubDomains; preload',
        ),
        'x-content-type-options' => 
        array (
          0 => 'nosniff',
        ),
        'x-frame-options' => 
        array (
          0 => 'deny',
        ),
        'x-permitted-cross-domain-policies' => 
        array (
          0 => 'none',
        ),
        'x-robots-tag' => 
        array (
          0 => 'noindex, nofollow',
        ),
        'CF-Cache-Status' => 
        array (
          0 => 'DYNAMIC',
        ),
        'Server' => 
        array (
          0 => 'cloudflare',
        ),
        'CF-RAY' => 
        array (
          0 => '881b5ce58bf2a66f-MIA',
        ),
      ),
       'headerNames' => 
      array (
        'date' => 'Date',
        'content-type' => 'Content-Type',
        'content-length' => 'Content-Length',
        'connection' => 'Connection',
        'cache-control' => 'Cache-Control',
        'content-security-policy' => 'content-security-policy',
        'cross-origin-embedder-policy' => 'cross-origin-embedder-policy',
        'cross-origin-opener-policy' => 'cross-origin-opener-policy',
        'cross-origin-resource-policy' => 'cross-origin-resource-policy',
        'permissions-policy' => 'permissions-policy',
        'pragma' => 'pragma',
        'referrer-policy' => 'referrer-policy',
        'request-id' => 'request-id',
        'strict-transport-security' => 'strict-transport-security',
        'x-content-type-options' => 'x-content-type-options',
        'x-frame-options' => 'x-frame-options',
        'x-permitted-cross-domain-policies' => 'x-permitted-cross-domain-policies',
        'x-robots-tag' => 'x-robots-tag',
        'cf-cache-status' => 'CF-Cache-Status',
        'server' => 'Server',
        'cf-ray' => 'CF-RAY',
      ),
       'protocol' => '1.1',
       'stream' => 
      \GuzzleHttp\Psr7\Stream::__set_state(array(
         'stream' => NULL,
         'size' => NULL,
         'seekable' => true,
         'readable' => true,
         'writable' => true,
         'uri' => 'php://temp',
         'customMetadata' => 
        array (
        ),
      )),
    )),
     'transferTime' => 0.187911,
     'handlerStats' => 
    array (
      'url' => 'https://sandbox-api.paddle.com/subscriptions/sub_01hxhnxneeggtwvqthyrv6s2c9/activate',
      'content_type' => 'application/json',
      'http_code' => 400,
      'header_size' => 1296,
      'request_size' => 282,
      'filetime' => -1,
      'ssl_verify_result' => 0,
      'redirect_count' => 0,
      'total_time' => 0.187911,
      'namelookup_time' => 0.001599,
      'connect_time' => 0.026742,
      'pretransfer_time' => 0.06666,
      'size_upload' => 2.0,
      'size_download' => 273.0,
      'speed_download' => 1459.0,
      'speed_upload' => 10.0,
      'download_content_length' => 273.0,
      'upload_content_length' => 2.0,
      'starttransfer_time' => 0.187571,
      'redirect_time' => 0.0,
      'redirect_url' => '',
      'primary_ip' => '2606:4700:3108::ac42:2bc4',
      'certinfo' => 
      array (
      ),
      'primary_port' => 443,
      'local_ip' => '2600:1700:63d3:d860:c2c:44ff:feca:4d5e',
      'local_port' => 35938,
      'http_version' => 2,
      'protocol' => 2,
      'ssl_verifyresult' => 0,
      'scheme' => 'HTTPS',
      'appconnect_time_us' => 66585,
      'connect_time_us' => 26742,
      'namelookup_time_us' => 1599,
      'pretransfer_time_us' => 66660,
      'redirect_time_us' => 0,
      'starttransfer_time_us' => 187571,
      'total_time_us' => 187911,
      'effective_method' => 'POST',
      'appconnect_time' => 0.066585,
    ),
     'handlerErrorData' => 0,
  )),
))
driesvints commented 4 months ago

@livan2r I would take up contact with Paddle because this would clearly indicate something wrong on their end if it's not a JSON response.

driesvints commented 4 months ago

@livan2r I'm contacting Paddle about this directly and working with them on this. They mentioned your API key is exposed above so you will want to rotate it.

livan2r commented 4 months ago

Sure, no problem @driesvints. It's just my sandbox key but I will rotate it. Thanks for the heads up and the quick issue follow-up.

driesvints commented 3 months ago

@livan2r I think I managed to fix it with https://github.com/laravel/cashier-paddle/pull/260. Could you perhaps try out that change to see if things work for you again?

livan2r commented 3 months ago

Hi, @driesvints unfortunately with this fix still it's not working for me, is it working for you? It works to me by passing null instead of {} on line 128, I don't know whether there is a reason not to pass null.

driesvints commented 3 months ago

@livan2r pushed a new commit based on your feedback. Can you try again?

livan2r commented 3 months ago

Oh Yeah! That one is working for me too. Thanks.

driesvints commented 3 months ago

Cool. Thanks!