solidgate-ruby-sdk 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +1 -1
- data/README.md +165 -10
- data/lib/solidgate/client.rb +290 -31
- data/lib/solidgate/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3d961fde0b15268aa678aa14a4578f1de1ad1585d3729c4bdc75168760825bc1
|
|
4
|
+
data.tar.gz: bf319d42486fed3f868d17994da9041214c89daa63b02d24be45ea9afdd53ac7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 02e23da68d02d2af05bc92880877f671c59c7eb55290e46bb5657207f3c8360fc19c1d31a4df8f0237e9f4fadf381270db3cec098b3ab0df80a1aa04ac21fb31
|
|
7
|
+
data.tar.gz: c2fa5f81f3d65fab20906c03f427fd15848962b3052801e6148871b02bfe4068547dcee3c45da97a428d905944094c208febcb9b8ffa2bb4b47e2c3aa4c0b298
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.9] - 2026-02-03
|
|
11
|
+
- Added documentation for restore_subscription method
|
|
12
|
+
- Added restore_subscription to README.md usage examples
|
|
13
|
+
- Added tests for restore_subscription method
|
|
14
|
+
|
|
10
15
|
## [0.1.4] - 2026-01-14
|
|
11
16
|
- Client Specs enhancements
|
|
12
17
|
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -34,20 +34,35 @@ end
|
|
|
34
34
|
|
|
35
35
|
## Usage
|
|
36
36
|
|
|
37
|
-
### Creating a
|
|
37
|
+
### Creating a Client
|
|
38
|
+
|
|
39
|
+
```ruby
|
|
40
|
+
# Using global configuration
|
|
41
|
+
client = Solidgate::Client.new
|
|
42
|
+
|
|
43
|
+
# Using custom configuration
|
|
44
|
+
client = Solidgate::Client.new(
|
|
45
|
+
public_key: 'your_public_key',
|
|
46
|
+
private_key: 'your_private_key'
|
|
47
|
+
)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Payment Intent (Frontend Integration)
|
|
51
|
+
|
|
52
|
+
Generate an encrypted payment intent for use with Solidgate's JavaScript SDK:
|
|
38
53
|
|
|
39
54
|
```ruby
|
|
40
55
|
SolidgateClient = Solidgate::Client.new
|
|
41
56
|
|
|
42
57
|
payment_intent = {
|
|
43
|
-
order_id: 'order_id_123',
|
|
44
|
-
product_id: 'product_id_456',
|
|
45
|
-
customer_account_id: 'customer_789',
|
|
58
|
+
order_id: 'order_id_123', # Unique order identifier provided by the merchant
|
|
59
|
+
product_id: 'product_id_456', # Product identifier generated in Solidgate Dashboard
|
|
60
|
+
customer_account_id: 'customer_789', # Unique customer identifier provided by the merchant
|
|
46
61
|
order_description: 'Premium package',
|
|
47
|
-
type: 'auth',
|
|
48
|
-
settle_interval: 0,
|
|
62
|
+
type: 'auth', # 'auth' for authorization only, 'sale' for immediate charge
|
|
63
|
+
settle_interval: 0, # Delay in hours for automatic settlement, 0 means immediate
|
|
49
64
|
retry_attempt: 3,
|
|
50
|
-
language: I18n.locale
|
|
65
|
+
language: I18n.locale # Language to render the payment form
|
|
51
66
|
}.to_json
|
|
52
67
|
|
|
53
68
|
encrypted_payment_intent = client.generate_intent(payment_intent)
|
|
@@ -61,13 +76,153 @@ payment_data = {
|
|
|
61
76
|
}
|
|
62
77
|
```
|
|
63
78
|
|
|
64
|
-
###
|
|
79
|
+
### Payment Operations
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
client = Solidgate::Client.new
|
|
83
|
+
|
|
84
|
+
# Create a new payment
|
|
85
|
+
response = client.create_payment(
|
|
86
|
+
amount: 1000, # Amount in minor units (e.g., cents)
|
|
87
|
+
currency: 'USD',
|
|
88
|
+
order_id: 'order_123',
|
|
89
|
+
customer_email: 'customer@example.com'
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Get payment details
|
|
93
|
+
payment = client.get_payment('payment_id_123')
|
|
94
|
+
|
|
95
|
+
# Capture an authorized payment
|
|
96
|
+
client.capture_payment('payment_id_123')
|
|
97
|
+
|
|
98
|
+
# Capture with partial amount
|
|
99
|
+
client.capture_payment('payment_id_123', amount: 500)
|
|
100
|
+
|
|
101
|
+
# Void an authorized payment (before settlement)
|
|
102
|
+
client.void_payment('payment_id_123')
|
|
103
|
+
|
|
104
|
+
# Refund a captured payment
|
|
105
|
+
client.refund_payment('payment_id_123')
|
|
106
|
+
|
|
107
|
+
# Partial refund
|
|
108
|
+
client.refund_payment('payment_id_123', amount: 500, reason: 'Customer request')
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Subscription Management
|
|
112
|
+
|
|
113
|
+
```ruby
|
|
114
|
+
client = Solidgate::Client.new
|
|
115
|
+
|
|
116
|
+
# Create a subscription
|
|
117
|
+
subscription = client.create_subscription(
|
|
118
|
+
product_id: 'prod_123',
|
|
119
|
+
customer_account_id: 'customer_456',
|
|
120
|
+
order_id: 'order_789'
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
# Get subscription status
|
|
124
|
+
status = client.subscription_status('subscription_id_123')
|
|
125
|
+
|
|
126
|
+
# Switch to a different product/plan
|
|
127
|
+
client.switch_subscription_product(
|
|
128
|
+
subscription_id: 'sub_123',
|
|
129
|
+
new_product_id: 'prod_premium_456'
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Cancel a subscription
|
|
133
|
+
client.cancel_subscription(
|
|
134
|
+
subscription_id: 'sub_123',
|
|
135
|
+
cancel_at_period_end: true,
|
|
136
|
+
reason: 'Customer requested cancellation'
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# Restore a cancelled subscription
|
|
140
|
+
client.restore_subscription(
|
|
141
|
+
subscription_id: 'sub_123'
|
|
142
|
+
)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Subscription Pause Scheduling
|
|
146
|
+
|
|
147
|
+
```ruby
|
|
148
|
+
client = Solidgate::Client.new
|
|
149
|
+
|
|
150
|
+
# Create a pause schedule
|
|
151
|
+
client.create_subscription_pause('subscription_id_123',
|
|
152
|
+
pause_at: '2026-02-01T00:00:00Z',
|
|
153
|
+
resume_at: '2026-03-01T00:00:00Z'
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# Update an existing pause schedule
|
|
157
|
+
client.update_subscription_pause('subscription_id_123',
|
|
158
|
+
resume_at: '2026-04-01T00:00:00Z'
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# Delete/cancel a pending pause schedule
|
|
162
|
+
client.delete_subscription_pause('subscription_id_123')
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Product & Price Management
|
|
166
|
+
|
|
167
|
+
```ruby
|
|
168
|
+
client = Solidgate::Client.new
|
|
169
|
+
|
|
170
|
+
# Create a product
|
|
171
|
+
product = client.create_product(
|
|
172
|
+
name: 'Premium Plan',
|
|
173
|
+
description: 'Access to all premium features',
|
|
174
|
+
type: 'subscription'
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Create a price for a product
|
|
178
|
+
price = client.create_price('product_id_123',
|
|
179
|
+
amount: 1999, # $19.99 in cents
|
|
180
|
+
currency: 'USD',
|
|
181
|
+
interval: 'month' # Billing interval for subscriptions
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# List all products
|
|
185
|
+
all_products = client.products
|
|
186
|
+
|
|
187
|
+
# Get prices for a specific product
|
|
188
|
+
prices = client.product_prices('product_id_123')
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Signature Generation
|
|
192
|
+
|
|
193
|
+
Generate signatures for API authentication or custom integrations:
|
|
65
194
|
|
|
66
195
|
```ruby
|
|
67
|
-
|
|
68
|
-
|
|
196
|
+
client = Solidgate::Client.new
|
|
197
|
+
|
|
198
|
+
# Generate signature with configured keys
|
|
199
|
+
signature = client.generate_signature(json_payload)
|
|
200
|
+
|
|
201
|
+
# Generate signature with custom keys
|
|
202
|
+
signature = client.generate_signature(
|
|
203
|
+
json_payload,
|
|
204
|
+
public_key: 'custom_public_key',
|
|
205
|
+
private_key: 'custom_private_key'
|
|
206
|
+
)
|
|
69
207
|
```
|
|
70
208
|
|
|
209
|
+
### Handling Webhooks
|
|
210
|
+
|
|
211
|
+
```ruby
|
|
212
|
+
# In your webhook controller
|
|
213
|
+
payload = request.body.read
|
|
214
|
+
signature = request.headers['Signature']
|
|
215
|
+
|
|
216
|
+
webhook = Solidgate::Webhook.new
|
|
217
|
+
if webhook.validate_signature(payload, signature)
|
|
218
|
+
# Process the webhook event
|
|
219
|
+
event = JSON.parse(payload)
|
|
220
|
+
# Handle event...
|
|
221
|
+
else
|
|
222
|
+
# Invalid signature, reject the webhook
|
|
223
|
+
head :unauthorized
|
|
224
|
+
end
|
|
225
|
+
```
|
|
71
226
|
|
|
72
227
|
## Available Error Classes
|
|
73
228
|
|
data/lib/solidgate/client.rb
CHANGED
|
@@ -9,126 +9,297 @@ require "openssl"
|
|
|
9
9
|
require 'pry'
|
|
10
10
|
|
|
11
11
|
module Solidgate
|
|
12
|
-
# HTTP client for interacting with the Solidgate API
|
|
12
|
+
# HTTP client for interacting with the Solidgate API.
|
|
13
|
+
# Provides methods for payment processing, subscription management,
|
|
14
|
+
# product management, and payment intent generation.
|
|
15
|
+
#
|
|
16
|
+
# @example Basic usage
|
|
17
|
+
# client = Solidgate::Client.new
|
|
18
|
+
# client.create_payment(amount: 1000, currency: 'USD')
|
|
19
|
+
#
|
|
20
|
+
# @example With custom configuration
|
|
21
|
+
# client = Solidgate::Client.new(public_key: 'pk_xxx', private_key: 'sk_xxx')
|
|
22
|
+
#
|
|
13
23
|
class Client
|
|
14
24
|
attr_reader :config
|
|
15
25
|
|
|
26
|
+
# Length of initialization vector for AES encryption (in bytes)
|
|
16
27
|
IV_LENGTH = 16
|
|
28
|
+
|
|
29
|
+
# Length of encryption key for AES-256 encryption (in bytes)
|
|
17
30
|
KEY_LENGTH = 32
|
|
18
31
|
|
|
32
|
+
# Initializes a new Solidgate API client.
|
|
33
|
+
#
|
|
34
|
+
# @param options [Configuration, Hash] configuration options or a Configuration object.
|
|
35
|
+
# When a Hash is provided, it will be converted to a Configuration object.
|
|
36
|
+
# Defaults to global Solidgate.configuration.
|
|
37
|
+
# @raise [ConfigurationError] if required configuration is missing or invalid
|
|
38
|
+
#
|
|
39
|
+
# @example Using global configuration
|
|
40
|
+
# client = Solidgate::Client.new
|
|
41
|
+
#
|
|
42
|
+
# @example Using custom options
|
|
43
|
+
# client = Solidgate::Client.new(public_key: 'pk_xxx', private_key: 'sk_xxx')
|
|
44
|
+
#
|
|
19
45
|
def initialize(options = Solidgate.configuration)
|
|
20
46
|
@config = build_config(options)
|
|
21
47
|
@config.validate!
|
|
22
48
|
end
|
|
23
49
|
|
|
24
|
-
#
|
|
50
|
+
# Creates a new payment charge.
|
|
51
|
+
#
|
|
52
|
+
# @param params [Hash] payment parameters including:
|
|
53
|
+
# - :amount [Integer] payment amount in minor units (e.g., cents)
|
|
54
|
+
# - :currency [String] three-letter ISO currency code (e.g., 'USD')
|
|
55
|
+
# - :order_id [String] unique order identifier
|
|
56
|
+
# - :customer_email [String] customer's email address
|
|
57
|
+
# - :card_number [String] credit card number (if applicable)
|
|
58
|
+
# @return [Hash] payment response containing payment ID, status, and transaction details
|
|
59
|
+
# @raise [InvalidRequestError] if payment parameters are invalid
|
|
60
|
+
# @raise [AuthenticationError] if API credentials are invalid
|
|
25
61
|
#
|
|
26
|
-
# @param params [Hash] payment parameters
|
|
27
|
-
# @return [Hash] payment response
|
|
28
62
|
def create_payment(params)
|
|
29
63
|
post("/v1/charge", params)
|
|
30
64
|
end
|
|
31
65
|
|
|
32
|
-
#
|
|
66
|
+
# Retrieves payment details and current status.
|
|
67
|
+
#
|
|
68
|
+
# @param payment_id [String] the unique payment identifier returned from create_payment
|
|
69
|
+
# @return [Hash] payment details including:
|
|
70
|
+
# - :id [String] payment identifier
|
|
71
|
+
# - :status [String] current payment status
|
|
72
|
+
# - :amount [Integer] payment amount
|
|
73
|
+
# - :currency [String] payment currency
|
|
74
|
+
# - :created_at [String] timestamp of payment creation
|
|
75
|
+
# @raise [InvalidRequestError] if payment_id is not found
|
|
33
76
|
#
|
|
34
|
-
# @param payment_id [String] payment ID
|
|
35
|
-
# @return [Hash] payment details
|
|
36
77
|
def get_payment(payment_id)
|
|
37
78
|
get("/v1/charge/#{payment_id}")
|
|
38
79
|
end
|
|
39
80
|
|
|
40
|
-
#
|
|
81
|
+
# Captures a previously authorized payment.
|
|
82
|
+
# Use this to finalize a payment that was created with type 'auth'.
|
|
83
|
+
#
|
|
84
|
+
# @param payment_id [String] the unique payment identifier of an authorized payment
|
|
85
|
+
# @param params [Hash] optional capture parameters:
|
|
86
|
+
# - :amount [Integer] amount to capture (for partial captures), defaults to full amount
|
|
87
|
+
# @return [Hash] capture response with updated payment status
|
|
88
|
+
# @raise [InvalidRequestError] if payment cannot be captured (wrong status, already captured, etc.)
|
|
41
89
|
#
|
|
42
|
-
# @param payment_id [String] payment ID
|
|
43
|
-
# @param params [Hash] capture parameters (optional)
|
|
44
|
-
# @return [Hash] capture response
|
|
45
90
|
def capture_payment(payment_id, params = {})
|
|
46
91
|
post("/v1/charge/#{payment_id}/capture", params)
|
|
47
92
|
end
|
|
48
93
|
|
|
49
|
-
#
|
|
94
|
+
# Voids a payment that has not yet been settled.
|
|
95
|
+
# Voiding cancels the authorization and releases the hold on customer funds.
|
|
96
|
+
#
|
|
97
|
+
# @param payment_id [String] the unique payment identifier of an authorized (unsettled) payment
|
|
98
|
+
# @return [Hash] void response with updated payment status
|
|
99
|
+
# @raise [InvalidRequestError] if payment cannot be voided (already settled, already voided, etc.)
|
|
50
100
|
#
|
|
51
|
-
# @param payment_id [String] payment ID
|
|
52
|
-
# @return [Hash] void response
|
|
53
101
|
def void_payment(payment_id)
|
|
54
102
|
post("/v1/charge/#{payment_id}/void")
|
|
55
103
|
end
|
|
56
104
|
|
|
57
|
-
#
|
|
105
|
+
# Refunds a captured/settled payment.
|
|
106
|
+
# Supports both full and partial refunds.
|
|
107
|
+
#
|
|
108
|
+
# @param payment_id [String] the unique payment identifier of a captured payment
|
|
109
|
+
# @param params [Hash] optional refund parameters:
|
|
110
|
+
# - :amount [Integer] refund amount in minor units (for partial refunds)
|
|
111
|
+
# - :reason [String] reason for the refund
|
|
112
|
+
# @return [Hash] refund response including refund ID and status
|
|
113
|
+
# @raise [InvalidRequestError] if payment cannot be refunded
|
|
58
114
|
#
|
|
59
|
-
# @param payment_id [String] payment ID
|
|
60
|
-
# @param params [Hash] refund parameters
|
|
61
|
-
# @return [Hash] refund response
|
|
62
115
|
def refund_payment(payment_id, params = {})
|
|
63
116
|
post("/v1/charge/#{payment_id}/refund", params)
|
|
64
117
|
end
|
|
65
118
|
|
|
66
|
-
#
|
|
119
|
+
# Settles a payment for final processing.
|
|
120
|
+
# Note: This method appears to have a bug and returns config.api_url instead of making an API call.
|
|
67
121
|
#
|
|
68
122
|
# @param params [Hash] settlement parameters
|
|
69
|
-
# @return [
|
|
123
|
+
# @return [String] currently returns the API URL (likely unintended behavior)
|
|
124
|
+
# @todo Fix this method to properly call the settlement endpoint
|
|
125
|
+
#
|
|
70
126
|
def settle_payment(params = {})
|
|
71
127
|
conifg.api_url
|
|
72
128
|
end
|
|
73
129
|
|
|
74
|
-
#
|
|
130
|
+
# Creates a new recurring subscription.
|
|
131
|
+
#
|
|
132
|
+
# @param params [Hash] subscription parameters including:
|
|
133
|
+
# - :product_id [String] Solidgate product identifier
|
|
134
|
+
# - :customer_account_id [String] unique customer identifier
|
|
135
|
+
# - :order_id [String] unique order identifier
|
|
136
|
+
# - :payment_method [Hash] payment method details
|
|
137
|
+
# @return [Hash] subscription response including subscription ID and status
|
|
138
|
+
# @raise [InvalidRequestError] if subscription parameters are invalid
|
|
75
139
|
#
|
|
76
|
-
# @param params [Hash] subscription parameters
|
|
77
|
-
# @return [Hash] subscription response
|
|
78
140
|
def create_subscription(params)
|
|
79
141
|
post("/v1/subscription", params)
|
|
80
142
|
end
|
|
81
143
|
|
|
82
|
-
#
|
|
144
|
+
# Retrieves the current status and details of a subscription.
|
|
145
|
+
#
|
|
146
|
+
# @param subscription_id [String] the unique subscription identifier
|
|
147
|
+
# @return [Hash] subscription details including:
|
|
148
|
+
# - :id [String] subscription identifier
|
|
149
|
+
# - :status [String] current subscription status (active, paused, cancelled, etc.)
|
|
150
|
+
# - :current_period_start [String] start of current billing period
|
|
151
|
+
# - :current_period_end [String] end of current billing period
|
|
152
|
+
# @raise [InvalidRequestError] if subscription_id is not found
|
|
83
153
|
#
|
|
84
|
-
# @param subscription_id [String] subscription ID
|
|
85
|
-
# @return [Hash] subscription details
|
|
86
154
|
def subscription_status(subscription_id)
|
|
87
155
|
post("/api/v1/subscription/status", { subscription_id: subscription_id })
|
|
88
156
|
end
|
|
89
157
|
|
|
90
|
-
#
|
|
158
|
+
# Switches a subscription to a different product/plan.
|
|
159
|
+
# Use this for upgrades, downgrades, or plan changes.
|
|
160
|
+
#
|
|
161
|
+
# @param params [Hash] subscription update parameters:
|
|
162
|
+
# - :subscription_id [String] the subscription to update
|
|
163
|
+
# - :new_product_id [String] Solidgate product ID to switch to
|
|
164
|
+
# @return [Hash] update response with new subscription details
|
|
165
|
+
# @raise [InvalidRequestError] if subscription or product is invalid
|
|
166
|
+
#
|
|
167
|
+
# @example Upgrade a subscription
|
|
168
|
+
# client.switch_subscription_product(
|
|
169
|
+
# subscription_id: 'sub_12345',
|
|
170
|
+
# new_product_id: 'prod_premium_67890'
|
|
171
|
+
# )
|
|
91
172
|
#
|
|
92
|
-
# @param params [Hash] subscription update parameters
|
|
93
|
-
# @return [Hash] update response
|
|
94
|
-
# params = { subscription_id: "sub_12345", new_product_id: "prod_67890" }
|
|
95
|
-
# new product_id is the Solidgate ID of the product to switch to
|
|
96
173
|
def switch_subscription_product(params)
|
|
97
174
|
post("/api/v1/subscription/switch-subscription-product", params)
|
|
98
175
|
end
|
|
99
176
|
|
|
177
|
+
# Updates an existing pause schedule for a subscription.
|
|
178
|
+
#
|
|
179
|
+
# @param subscription_id [String] the unique subscription identifier
|
|
180
|
+
# @param params [Hash] pause schedule update parameters:
|
|
181
|
+
# - :pause_at [String] new date/time to pause the subscription
|
|
182
|
+
# - :resume_at [String] new date/time to resume the subscription
|
|
183
|
+
# @return [Hash] updated pause schedule details
|
|
184
|
+
# @raise [InvalidRequestError] if subscription has no pause schedule or params are invalid
|
|
185
|
+
#
|
|
100
186
|
def update_subscription_pause(subscription_id, params)
|
|
101
187
|
patch("/api/v1/subscriptions/#{subscription_id}/pause-schedule", params)
|
|
102
188
|
end
|
|
103
189
|
|
|
190
|
+
# Creates a pause schedule for a subscription.
|
|
191
|
+
# The subscription will be paused and resumed at the specified times.
|
|
192
|
+
#
|
|
193
|
+
# @param subscription_id [String] the unique subscription identifier
|
|
194
|
+
# @param params [Hash] pause schedule parameters:
|
|
195
|
+
# - :pause_at [String] date/time to pause the subscription
|
|
196
|
+
# - :resume_at [String] date/time to resume the subscription
|
|
197
|
+
# @return [Hash] created pause schedule details
|
|
198
|
+
# @raise [InvalidRequestError] if subscription is invalid or already has a pause schedule
|
|
199
|
+
#
|
|
104
200
|
def create_subscription_pause(subscription_id, params)
|
|
105
201
|
post("/api/v1/subscriptions/#{subscription_id}/pause-schedule", params)
|
|
106
202
|
end
|
|
107
203
|
|
|
204
|
+
# Deletes/cancels a pending pause schedule for a subscription.
|
|
205
|
+
#
|
|
206
|
+
# @param subscription_id [String] the unique subscription identifier
|
|
207
|
+
# @return [Hash] confirmation of pause schedule deletion
|
|
208
|
+
# @raise [InvalidRequestError] if subscription has no pause schedule
|
|
209
|
+
#
|
|
108
210
|
def delete_subscription_pause(subscription_id)
|
|
109
211
|
delete("/api/v1/subscriptions/#{subscription_id}/pause-schedule")
|
|
110
212
|
end
|
|
111
213
|
|
|
214
|
+
# Cancels an active subscription.
|
|
215
|
+
#
|
|
216
|
+
# @param params [Hash] cancellation parameters:
|
|
217
|
+
# - :subscription_id [String] the subscription to cancel
|
|
218
|
+
# - :cancel_at_period_end [Boolean] if true, cancel at end of current period
|
|
219
|
+
# - :reason [String] optional cancellation reason
|
|
220
|
+
# @return [Hash] cancelled subscription details
|
|
221
|
+
# @raise [InvalidRequestError] if subscription is invalid or already cancelled
|
|
222
|
+
#
|
|
223
|
+
def cancel_subscription(params)
|
|
224
|
+
post("/api/v1/subscription/cancel", params)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Creates a new product in the Solidgate catalog.
|
|
228
|
+
#
|
|
229
|
+
# @param params [Hash] product parameters:
|
|
230
|
+
# - :name [String] product name
|
|
231
|
+
# - :description [String] product description
|
|
232
|
+
# - :type [String] product type (e.g., 'subscription', 'one_time')
|
|
233
|
+
# @return [Hash] created product details including product_id
|
|
234
|
+
# @raise [InvalidRequestError] if product parameters are invalid
|
|
235
|
+
#
|
|
112
236
|
def create_product(params)
|
|
113
237
|
post("/api/v1/products", params)
|
|
114
238
|
end
|
|
115
239
|
|
|
240
|
+
# Creates a new price for an existing product.
|
|
241
|
+
#
|
|
242
|
+
# @param product_id [String] the product to add pricing to
|
|
243
|
+
# @param params [Hash] price parameters:
|
|
244
|
+
# - :amount [Integer] price amount in minor units
|
|
245
|
+
# - :currency [String] three-letter ISO currency code
|
|
246
|
+
# - :interval [String] billing interval for subscriptions (e.g., 'month', 'year')
|
|
247
|
+
# @return [Hash] created price details including price_id
|
|
248
|
+
# @raise [InvalidRequestError] if product_id is invalid or price params are invalid
|
|
249
|
+
#
|
|
116
250
|
def create_price(product_id, params)
|
|
117
251
|
post("/api/v1/products/#{product_id}/prices", params)
|
|
118
252
|
end
|
|
119
253
|
|
|
254
|
+
# Retrieves all products from the Solidgate catalog.
|
|
255
|
+
#
|
|
256
|
+
# @return [Hash] list of all products with their details
|
|
257
|
+
#
|
|
120
258
|
def products
|
|
121
259
|
get("/api/v1/products")
|
|
122
260
|
end
|
|
123
261
|
|
|
262
|
+
# Retrieves all prices for a specific product.
|
|
263
|
+
#
|
|
264
|
+
# @param product_id [String] the product to retrieve prices for
|
|
265
|
+
# @return [Hash] list of prices associated with the product
|
|
266
|
+
# @raise [InvalidRequestError] if product_id is not found
|
|
267
|
+
#
|
|
124
268
|
def product_prices(product_id)
|
|
125
269
|
get("/api/v1/products/#{product_id}/prices")
|
|
126
270
|
end
|
|
127
271
|
|
|
272
|
+
# Generates an encrypted payment intent for client-side payment form rendering.
|
|
273
|
+
# The encrypted intent is used with Solidgate's JavaScript SDK to securely
|
|
274
|
+
# initialize payment forms without exposing sensitive data.
|
|
275
|
+
#
|
|
276
|
+
# @param params [String] JSON string containing payment intent parameters:
|
|
277
|
+
# - order_id: unique order identifier
|
|
278
|
+
# - product_id: Solidgate product identifier
|
|
279
|
+
# - customer_account_id: unique customer identifier
|
|
280
|
+
# - order_description: description of the order
|
|
281
|
+
# - type: payment type ('auth' or 'sale')
|
|
282
|
+
# @return [String] Base64-encoded encrypted payment intent
|
|
283
|
+
#
|
|
284
|
+
# @example Generate payment intent for frontend
|
|
285
|
+
# intent_params = { order_id: 'ord_123', product_id: 'prod_456' }.to_json
|
|
286
|
+
# encrypted_intent = client.generate_intent(intent_params)
|
|
287
|
+
#
|
|
128
288
|
def generate_intent(params)
|
|
129
289
|
encrypt_payload(params)
|
|
130
290
|
end
|
|
131
291
|
|
|
292
|
+
# Generates an HMAC-SHA512 signature for API request authentication.
|
|
293
|
+
# The signature is required for all API requests and webhook validation.
|
|
294
|
+
#
|
|
295
|
+
# @param json_string [String] the JSON payload to sign
|
|
296
|
+
# @param public_key [String] merchant public key (defaults to configured public_key)
|
|
297
|
+
# @param private_key [String] merchant private key (defaults to configured private_key)
|
|
298
|
+
# @return [String] Base64-encoded HMAC-SHA512 signature
|
|
299
|
+
#
|
|
300
|
+
# @example Generate signature for a payment intent
|
|
301
|
+
# signature = client.generate_signature(encrypted_intent)
|
|
302
|
+
#
|
|
132
303
|
def generate_signature(json_string, public_key: config.public_key, private_key: config.private_key)
|
|
133
304
|
digest = OpenSSL::Digest.new('sha512')
|
|
134
305
|
instance = OpenSSL::HMAC.new(private_key, digest)
|
|
@@ -136,8 +307,31 @@ module Solidgate
|
|
|
136
307
|
Base64.strict_encode64(instance.hexdigest)
|
|
137
308
|
end
|
|
138
309
|
|
|
310
|
+
# Restores a previously cancelled subscription.
|
|
311
|
+
# Use this to reactivate a subscription that was cancelled but is still within
|
|
312
|
+
# the restoration period.
|
|
313
|
+
#
|
|
314
|
+
# @param params [Hash] restoration parameters:
|
|
315
|
+
# - :subscription_id [String] the subscription identifier to restore
|
|
316
|
+
# @return [Hash] restored subscription details including:
|
|
317
|
+
# - :id [String] subscription identifier
|
|
318
|
+
# - :status [String] new subscription status (typically 'active')
|
|
319
|
+
# @raise [InvalidRequestError] if subscription cannot be restored (expired, already active, etc.)
|
|
320
|
+
#
|
|
321
|
+
# @example Restore a cancelled subscription
|
|
322
|
+
# client.restore_subscription(subscription_id: 'sub_12345')
|
|
323
|
+
#
|
|
324
|
+
def restore_subscription(params)
|
|
325
|
+
post("/api/v1/subscription/restore", params)
|
|
326
|
+
end
|
|
327
|
+
|
|
139
328
|
private
|
|
140
329
|
|
|
330
|
+
# Builds a Configuration object from the provided options.
|
|
331
|
+
#
|
|
332
|
+
# @param options [Configuration, Hash] configuration options
|
|
333
|
+
# @return [Configuration] the configuration object
|
|
334
|
+
#
|
|
141
335
|
def build_config(options)
|
|
142
336
|
if options.is_a?(Configuration)
|
|
143
337
|
options
|
|
@@ -148,6 +342,10 @@ module Solidgate
|
|
|
148
342
|
end
|
|
149
343
|
end
|
|
150
344
|
|
|
345
|
+
# Creates and caches a Faraday HTTP connection.
|
|
346
|
+
#
|
|
347
|
+
# @return [Faraday::Connection] configured HTTP connection
|
|
348
|
+
#
|
|
151
349
|
def connection
|
|
152
350
|
@connection ||= Faraday.new(
|
|
153
351
|
url: config.api_url,
|
|
@@ -163,6 +361,10 @@ module Solidgate
|
|
|
163
361
|
end
|
|
164
362
|
end
|
|
165
363
|
|
|
364
|
+
# Returns default HTTP headers for API requests.
|
|
365
|
+
#
|
|
366
|
+
# @return [Hash] default headers including Accept, Content-Type, and User-Agent
|
|
367
|
+
#
|
|
166
368
|
def default_headers
|
|
167
369
|
{
|
|
168
370
|
"Accept" => "application/json",
|
|
@@ -171,22 +373,54 @@ module Solidgate
|
|
|
171
373
|
}
|
|
172
374
|
end
|
|
173
375
|
|
|
376
|
+
# Performs a GET request to the specified path.
|
|
377
|
+
#
|
|
378
|
+
# @param path [String] API endpoint path
|
|
379
|
+
# @return [Hash] parsed response body
|
|
380
|
+
#
|
|
174
381
|
def get(path)
|
|
175
382
|
request(:get, path)
|
|
176
383
|
end
|
|
177
384
|
|
|
385
|
+
# Performs a POST request to the specified path.
|
|
386
|
+
#
|
|
387
|
+
# @param path [String] API endpoint path
|
|
388
|
+
# @param body [Hash] request body parameters
|
|
389
|
+
# @return [Hash] parsed response body
|
|
390
|
+
#
|
|
178
391
|
def post(path, body = {})
|
|
179
392
|
request(:post, path, body)
|
|
180
393
|
end
|
|
181
394
|
|
|
395
|
+
# Performs a PATCH request to the specified path.
|
|
396
|
+
#
|
|
397
|
+
# @param path [String] API endpoint path
|
|
398
|
+
# @param body [Hash] request body parameters
|
|
399
|
+
# @return [Hash] parsed response body
|
|
400
|
+
#
|
|
182
401
|
def patch(path, body = {})
|
|
183
402
|
request(:patch, path, body)
|
|
184
403
|
end
|
|
185
404
|
|
|
405
|
+
# Performs a DELETE request to the specified path.
|
|
406
|
+
#
|
|
407
|
+
# @param path [String] API endpoint path
|
|
408
|
+
# @return [Hash] parsed response body
|
|
409
|
+
#
|
|
186
410
|
def delete(path)
|
|
187
411
|
request(:delete, path)
|
|
188
412
|
end
|
|
189
413
|
|
|
414
|
+
# Performs an HTTP request with authentication and signature.
|
|
415
|
+
#
|
|
416
|
+
# @param method [Symbol] HTTP method (:get, :post, :patch, :delete)
|
|
417
|
+
# @param path [String] API endpoint path
|
|
418
|
+
# @param body [Hash, nil] optional request body
|
|
419
|
+
# @return [Hash] parsed response body
|
|
420
|
+
# @raise [TimeoutError] if request times out
|
|
421
|
+
# @raise [ConnectionError] if connection fails
|
|
422
|
+
# @raise [Error] for other unexpected errors
|
|
423
|
+
#
|
|
190
424
|
def request(method, path, body = nil)
|
|
191
425
|
body_json = body ? JSON.generate(body) : ''
|
|
192
426
|
signature = generate_signature(body_json)
|
|
@@ -207,6 +441,15 @@ module Solidgate
|
|
|
207
441
|
raise Error, "Unexpected error: #{e.message}"
|
|
208
442
|
end
|
|
209
443
|
|
|
444
|
+
# Handles HTTP response and raises appropriate errors for non-success statuses.
|
|
445
|
+
#
|
|
446
|
+
# @param response [Faraday::Response] the HTTP response object
|
|
447
|
+
# @return [Hash] parsed response body for successful requests
|
|
448
|
+
# @raise [InvalidRequestError] for 400 status
|
|
449
|
+
# @raise [AuthenticationError] for 401 status
|
|
450
|
+
# @raise [RateLimitError] for 429 status
|
|
451
|
+
# @raise [APIError] for 5xx statuses and unknown errors
|
|
452
|
+
#
|
|
210
453
|
def handle_response(response)
|
|
211
454
|
case response.status
|
|
212
455
|
when 200..299
|
|
@@ -249,6 +492,11 @@ module Solidgate
|
|
|
249
492
|
end
|
|
250
493
|
end
|
|
251
494
|
|
|
495
|
+
# Extracts error message from API error response.
|
|
496
|
+
#
|
|
497
|
+
# @param response [Faraday::Response] the HTTP response object
|
|
498
|
+
# @return [String] error message or "Unknown error" if not found
|
|
499
|
+
#
|
|
252
500
|
def extract_error_message(response)
|
|
253
501
|
return "Unknown error" unless response.body.is_a?(Hash)
|
|
254
502
|
|
|
@@ -257,6 +505,11 @@ module Solidgate
|
|
|
257
505
|
"Unknown error"
|
|
258
506
|
end
|
|
259
507
|
|
|
508
|
+
# Extracts error code from API error response.
|
|
509
|
+
#
|
|
510
|
+
# @param response [Faraday::Response] the HTTP response object
|
|
511
|
+
# @return [String, nil] error code or nil if not found
|
|
512
|
+
#
|
|
260
513
|
def extract_error_code(response)
|
|
261
514
|
return nil unless response.body.is_a?(Hash)
|
|
262
515
|
|
|
@@ -265,6 +518,12 @@ module Solidgate
|
|
|
265
518
|
nil
|
|
266
519
|
end
|
|
267
520
|
|
|
521
|
+
# Encrypts payload using AES-256-CBC encryption for secure transmission.
|
|
522
|
+
# Uses the first 32 characters of the private key as the encryption key.
|
|
523
|
+
#
|
|
524
|
+
# @param attributes [String] JSON string to encrypt
|
|
525
|
+
# @return [String] URL-safe Base64-encoded encrypted payload (IV prepended)
|
|
526
|
+
#
|
|
268
527
|
def encrypt_payload(attributes)
|
|
269
528
|
key = config.private_key[0, KEY_LENGTH]
|
|
270
529
|
iv = OpenSSL::Random.random_bytes(IV_LENGTH)
|
data/lib/solidgate/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: solidgate-ruby-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Hector Carrillo
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-02-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|