PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.5
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.5
1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 All 49 releases
← All changes | app/Modules/PaymentMethods/StripeGateway/API/API.php +37 -12 1.5.5 → 1.6.5 View file →
@@ -26,12 +26,12 @@
26 26
27 27 return $this->remoteRequest($path, $data, $apiKey, 'GET');
28 28 }
29 29
30 - public function createStripeObject($path, $data = [], $mode = 'current', $idempotencyKey = null)
30 + public function createStripeObject($path, $data = [], $mode = 'current', $headers = [])
31 31 {
32 32 $apiKey = (new StripeSettingsBase())->getApiKey($mode);
33 - return $this->remoteRequest($path, $data, $apiKey, 'POST', $idempotencyKey);
33 + return $this->remoteRequest($path, $data, $apiKey, 'POST', $headers);
34 34 }
35 35
36 36 public function deleteStripeObject($path, $data = [], $mode = 'current')
37 37 {
@@ -38,11 +38,24 @@
38 38 $apiKey = (new StripeSettingsBase())->getApiKey($mode);
39 39 return $this->remoteRequest($path, $data, $apiKey, 'DELETE');
40 40 }
41 41
42 - public function remoteRequest($path, $data, $apiKey, $method, $idempotencyKey = null)
42 + public function remoteRequest($path, $data, $apiKey, $method, $extraHeaders = [])
43 43 {
44 44 $stripeApiKey = $apiKey;
45 +
46 + // Never fire a request with an empty Authorization header — Stripe replies
47 + // with the cryptic "You did not provide an API key" error. This happens when
48 + // the secret key for the requested mode is not configured (e.g. a store in
49 + // test mode charging a live-mode order, or unconfigured keys). Fail early
50 + // with an actionable message instead.
51 + if (empty($stripeApiKey)) {
52 + return new \WP_Error(
53 + 'stripe_missing_api_key',
54 + __('Stripe API key is not configured for this payment mode. Please add your Stripe keys in Payment Settings.', 'fluent-cart')
55 + );
56 + }
57 +
45 58 $apiVersion = '2025-02-24.acacia';
46 59 $sessionHeaders = array(
47 60 'Authorization' => 'Bearer ' . $stripeApiKey,
48 61 'Content-Type' => 'application/x-www-form-urlencoded',
@@ -48,13 +61,11 @@
48 61 'Content-Type' => 'application/x-www-form-urlencoded',
49 62 'Stripe-Version' => $apiVersion
50 63 );
51 64
52 - // Stripe dedupes any POST carrying the same Idempotency-Key (valid 24h),
53 - // so a duplicate/retried create request returns the original object instead
54 - // of charging the customer or creating a second subscription again.
55 - if ($idempotencyKey && $method === 'POST') {
56 - $sessionHeaders['Idempotency-Key'] = $idempotencyKey;
65 + // Per-request headers (e.g. Idempotency-Key for off-session renewal charges)
66 + if ($extraHeaders && is_array($extraHeaders)) {
67 + $sessionHeaders = array_merge($sessionHeaders, $extraHeaders);
57 68 }
58 69
59 70 $url = $this->apiUrl . $path;
60 71
@@ -116,18 +127,32 @@
116 127
117 128 return $data;
118 129 }
119 130
120 - public function getEvent($eventId)
131 + /**
132 + * Event ids are namespaced per mode, so a live id is unfetchable with a test key
133 + * and vice versa. The store's global mode toggle is not a reliable proxy — a
134 + * renewal is billed by Stripe on its own schedule, whatever the store is set to.
135 + *
136 + * @param string $eventId
137 + * @param bool|null $livemode Mode the event belongs to; null falls back to the store setting.
138 + * @return object|null|\WP_Error Null when the response body is not decodable JSON.
139 + */
140 + public function getEvent($eventId, $livemode = null)
121 141 {
122 - $api = $this->getApi();
142 + $mode = 'current';
143 + if (!is_null($livemode)) {
144 + $mode = $livemode ? 'live' : 'test';
145 + }
146 +
147 + $api = $this->getApi($mode);
123 148 return $api::request([], 'events/' . $eventId, 'GET');
124 149 }
125 150
126 - public function getApi()
151 + public function getApi($mode = 'current')
127 152 {
128 153 $api = new ApiRequest();
129 - $api::set_secret_key((new StripeSettingsBase())->getApiKey());
154 + $api::set_secret_key((new StripeSettingsBase())->getApiKey($mode));
130 155 return $api;
131 156 }
132 157
133 158 public function getApiKey($mode = 'current')