creem 0.0.1
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 +7 -0
- data/.github/workflows/ci.yml +50 -0
- data/.github/workflows/release.yml +49 -0
- data/.gitignore +6 -0
- data/.rspec +3 -0
- data/.rubocop.yml +126 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +17 -0
- data/CLAUDE.md +38 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +85 -0
- data/LICENSE +21 -0
- data/Makefile +108 -0
- data/README.md +193 -0
- data/Rakefile +9 -0
- data/creem.gemspec +49 -0
- data/docs/api_reference.md +335 -0
- data/docs/architecture.md +145 -0
- data/docs/development.md +137 -0
- data/docs/error_handling.md +85 -0
- data/docs/getting_started.md +116 -0
- data/docs/webhooks.md +179 -0
- data/lib/creem/client.rb +119 -0
- data/lib/creem/configuration.rb +18 -0
- data/lib/creem/errors.rb +24 -0
- data/lib/creem/resources/base.rb +23 -0
- data/lib/creem/resources/checkouts.rb +22 -0
- data/lib/creem/resources/customers.rb +24 -0
- data/lib/creem/resources/discounts.rb +13 -0
- data/lib/creem/resources/licenses.rb +25 -0
- data/lib/creem/resources/products.rb +17 -0
- data/lib/creem/resources/subscriptions.rb +31 -0
- data/lib/creem/resources/transactions.rb +13 -0
- data/lib/creem/version.rb +5 -0
- data/lib/creem/webhook.rb +33 -0
- data/lib/creem.rb +33 -0
- metadata +157 -0
data/lib/creem/client.rb
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "uri"
|
|
5
|
+
require "json"
|
|
6
|
+
|
|
7
|
+
module Creem
|
|
8
|
+
class Client
|
|
9
|
+
attr_reader :config
|
|
10
|
+
|
|
11
|
+
def initialize(api_key: nil, test_mode: nil, timeout: nil, open_timeout: nil)
|
|
12
|
+
@config = Configuration.new
|
|
13
|
+
@config.api_key = api_key || Creem.configuration.api_key
|
|
14
|
+
@config.test_mode = test_mode.nil? ? Creem.configuration.test_mode : test_mode
|
|
15
|
+
@config.timeout = timeout || Creem.configuration.timeout
|
|
16
|
+
@config.open_timeout = open_timeout || Creem.configuration.open_timeout
|
|
17
|
+
|
|
18
|
+
raise ConfigurationError, "API key is required" if @config.api_key.nil? || @config.api_key.empty?
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def products
|
|
22
|
+
@products ||= Resources::Products.new(self)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def checkouts
|
|
26
|
+
@checkouts ||= Resources::Checkouts.new(self)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def subscriptions
|
|
30
|
+
@subscriptions ||= Resources::Subscriptions.new(self)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def customers
|
|
34
|
+
@customers ||= Resources::Customers.new(self)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def transactions
|
|
38
|
+
@transactions ||= Resources::Transactions.new(self)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def licenses
|
|
42
|
+
@licenses ||= Resources::Licenses.new(self)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def discounts
|
|
46
|
+
@discounts ||= Resources::Discounts.new(self)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def get(path, params = {})
|
|
50
|
+
request(:get, path, params: params)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def post(path, body = {})
|
|
54
|
+
request(:post, path, body: body)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def request(method, path, params: {}, body: nil)
|
|
60
|
+
uri = build_uri(path, params)
|
|
61
|
+
http = build_http(uri)
|
|
62
|
+
req = build_request(method, uri, body)
|
|
63
|
+
response = http.request(req)
|
|
64
|
+
handle_response(response)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def build_uri(path, params)
|
|
68
|
+
uri = URI.parse("#{@config.base_url}#{path}")
|
|
69
|
+
if params && !params.empty?
|
|
70
|
+
query = params.reject { |_k, v| v.nil? }.map { |k, v| "#{k}=#{URI.encode_www_form_component(v)}" }.join("&")
|
|
71
|
+
uri.query = query unless query.empty?
|
|
72
|
+
end
|
|
73
|
+
uri
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def build_http(uri)
|
|
77
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
78
|
+
http.use_ssl = true
|
|
79
|
+
http.read_timeout = @config.timeout
|
|
80
|
+
http.open_timeout = @config.open_timeout
|
|
81
|
+
http
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def build_request(method, uri, body)
|
|
85
|
+
req = case method
|
|
86
|
+
when :get then Net::HTTP::Get.new(uri)
|
|
87
|
+
when :post then Net::HTTP::Post.new(uri)
|
|
88
|
+
else raise ArgumentError, "Unsupported HTTP method: #{method}"
|
|
89
|
+
end
|
|
90
|
+
req["x-api-key"] = @config.api_key
|
|
91
|
+
req["Content-Type"] = "application/json"
|
|
92
|
+
req["Accept"] = "application/json"
|
|
93
|
+
req.body = JSON.generate(body) if body && !body.empty?
|
|
94
|
+
req
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def handle_response(response)
|
|
98
|
+
body = response.body && !response.body.empty? ? JSON.parse(response.body) : nil
|
|
99
|
+
status = response.code.to_i
|
|
100
|
+
|
|
101
|
+
case status
|
|
102
|
+
when 200..299
|
|
103
|
+
body
|
|
104
|
+
when 400
|
|
105
|
+
raise BadRequestError.new("Bad Request", status: status, body: body)
|
|
106
|
+
when 401
|
|
107
|
+
raise AuthenticationError.new("Unauthorized - Invalid or missing API key", status: status, body: body)
|
|
108
|
+
when 404
|
|
109
|
+
raise NotFoundError.new("Not Found", status: status, body: body)
|
|
110
|
+
when 429
|
|
111
|
+
raise RateLimitError.new("Rate limit exceeded", status: status, body: body)
|
|
112
|
+
when 500..599
|
|
113
|
+
raise ServerError.new("Server error", status: status, body: body)
|
|
114
|
+
else
|
|
115
|
+
raise ApiError.new("Unexpected response", status: status, body: body)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Creem
|
|
4
|
+
class Configuration
|
|
5
|
+
attr_accessor :api_key, :test_mode, :timeout, :open_timeout
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@api_key = nil
|
|
9
|
+
@test_mode = false
|
|
10
|
+
@timeout = 30
|
|
11
|
+
@open_timeout = 10
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def base_url
|
|
15
|
+
test_mode ? TEST_BASE_URL : PRODUCTION_BASE_URL
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/creem/errors.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Creem
|
|
4
|
+
class Error < StandardError; end
|
|
5
|
+
|
|
6
|
+
class ConfigurationError < Error; end
|
|
7
|
+
|
|
8
|
+
class ApiError < Error
|
|
9
|
+
attr_reader :status, :body
|
|
10
|
+
|
|
11
|
+
def initialize(message = nil, status: nil, body: nil)
|
|
12
|
+
@status = status
|
|
13
|
+
@body = body
|
|
14
|
+
super(message || "API request failed with status #{status}")
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class AuthenticationError < ApiError; end
|
|
19
|
+
class BadRequestError < ApiError; end
|
|
20
|
+
class NotFoundError < ApiError; end
|
|
21
|
+
class RateLimitError < ApiError; end
|
|
22
|
+
class ServerError < ApiError; end
|
|
23
|
+
class WebhookSignatureError < Error; end
|
|
24
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Creem
|
|
4
|
+
module Resources
|
|
5
|
+
class Base
|
|
6
|
+
attr_reader :client
|
|
7
|
+
|
|
8
|
+
def initialize(client)
|
|
9
|
+
@client = client
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def get(path, params = {})
|
|
15
|
+
client.get(path, params)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def post(path, body = {})
|
|
19
|
+
client.post(path, body)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Creem
|
|
6
|
+
module Resources
|
|
7
|
+
class Checkouts < Base
|
|
8
|
+
def create(product_id:, success_url: nil, request_id: nil, units: nil, discount_code: nil,
|
|
9
|
+
customer: nil, custom_fields: nil, metadata: nil)
|
|
10
|
+
body = { product_id: product_id }
|
|
11
|
+
body[:success_url] = success_url if success_url
|
|
12
|
+
body[:request_id] = request_id if request_id
|
|
13
|
+
body[:units] = units if units
|
|
14
|
+
body[:discount_code] = discount_code if discount_code
|
|
15
|
+
body[:customer] = customer if customer
|
|
16
|
+
body[:custom_fields] = custom_fields if custom_fields
|
|
17
|
+
body[:metadata] = metadata if metadata
|
|
18
|
+
post("/checkouts", body)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Creem
|
|
6
|
+
module Resources
|
|
7
|
+
class Customers < Base
|
|
8
|
+
def list(page_number: 1, page_size: 50)
|
|
9
|
+
get("/customers/list", page_number: page_number, page_size: page_size)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def retrieve(customer_id: nil, email: nil)
|
|
13
|
+
params = {}
|
|
14
|
+
params[:customer_id] = customer_id if customer_id
|
|
15
|
+
params[:email] = email if email
|
|
16
|
+
get("/customers", params)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def billing_portal(customer_id)
|
|
20
|
+
post("/customers/billing-portal", { customer_id: customer_id })
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Creem
|
|
6
|
+
module Resources
|
|
7
|
+
class Discounts < Base
|
|
8
|
+
def list(page_number: 1, page_size: 10)
|
|
9
|
+
get("/discounts/search", page_number: page_number, page_size: page_size)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Creem
|
|
6
|
+
module Resources
|
|
7
|
+
class Licenses < Base
|
|
8
|
+
def list(page_number: 1, page_size: 10)
|
|
9
|
+
get("/licenses/search", page_number: page_number, page_size: page_size)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def validate(key:, instance_id:)
|
|
13
|
+
post("/licenses/validate", { key: key, instance_id: instance_id })
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def activate(key:, instance_name:)
|
|
17
|
+
post("/licenses/activate", { key: key, instance_name: instance_name })
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def deactivate(key:, instance_id:)
|
|
21
|
+
post("/licenses/deactivate", { key: key, instance_id: instance_id })
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Creem
|
|
6
|
+
module Resources
|
|
7
|
+
class Products < Base
|
|
8
|
+
def list(page_number: 1, page_size: 10)
|
|
9
|
+
get("/products/search", page_number: page_number, page_size: page_size)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def retrieve(product_id)
|
|
13
|
+
get("/products", product_id: product_id)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Creem
|
|
6
|
+
module Resources
|
|
7
|
+
class Subscriptions < Base
|
|
8
|
+
def list(page_number: 1, page_size: 10)
|
|
9
|
+
get("/subscriptions/search", page_number: page_number, page_size: page_size)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def retrieve(subscription_id)
|
|
13
|
+
get("/subscriptions", subscription_id: subscription_id)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def update(id, items: nil, update_behavior: nil)
|
|
17
|
+
body = {}
|
|
18
|
+
body[:items] = items if items
|
|
19
|
+
body[:update_behavior] = update_behavior if update_behavior
|
|
20
|
+
post("/subscriptions/#{id}", body)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def cancel(id, mode: nil, on_execute: nil)
|
|
24
|
+
body = {}
|
|
25
|
+
body[:mode] = mode if mode
|
|
26
|
+
body[:onExecute] = on_execute if on_execute
|
|
27
|
+
post("/subscriptions/#{id}/cancel", body)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Creem
|
|
6
|
+
module Resources
|
|
7
|
+
class Transactions < Base
|
|
8
|
+
def list(page_number: 1, page_size: 10)
|
|
9
|
+
get("/transactions/search", page_number: page_number, page_size: page_size)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "openssl"
|
|
4
|
+
|
|
5
|
+
module Creem
|
|
6
|
+
class Webhook
|
|
7
|
+
def self.verify_signature(payload:, secret:, signature:)
|
|
8
|
+
computed = OpenSSL::HMAC.hexdigest("SHA256", secret, payload)
|
|
9
|
+
secure_compare(computed, signature)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.verify_signature!(payload:, secret:, signature:)
|
|
13
|
+
unless verify_signature(payload: payload, secret: secret, signature: signature)
|
|
14
|
+
raise WebhookSignatureError, "Invalid webhook signature"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.construct_event(payload:, secret:, signature:)
|
|
21
|
+
verify_signature!(payload: payload, secret: secret, signature: signature)
|
|
22
|
+
JSON.parse(payload)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.secure_compare(a, b)
|
|
26
|
+
return false unless a.bytesize == b.bytesize
|
|
27
|
+
|
|
28
|
+
OpenSSL.fixed_length_secure_compare(a, b)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private_class_method :secure_compare
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/creem.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "creem/version"
|
|
4
|
+
require_relative "creem/configuration"
|
|
5
|
+
require_relative "creem/errors"
|
|
6
|
+
require_relative "creem/client"
|
|
7
|
+
require_relative "creem/webhook"
|
|
8
|
+
require_relative "creem/resources/products"
|
|
9
|
+
require_relative "creem/resources/checkouts"
|
|
10
|
+
require_relative "creem/resources/subscriptions"
|
|
11
|
+
require_relative "creem/resources/customers"
|
|
12
|
+
require_relative "creem/resources/transactions"
|
|
13
|
+
require_relative "creem/resources/licenses"
|
|
14
|
+
require_relative "creem/resources/discounts"
|
|
15
|
+
|
|
16
|
+
module Creem
|
|
17
|
+
PRODUCTION_BASE_URL = "https://api.creem.io/v1"
|
|
18
|
+
TEST_BASE_URL = "https://test-api.creem.io/v1"
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
def configure
|
|
22
|
+
yield(configuration)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def configuration
|
|
26
|
+
@configuration ||= Configuration.new
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def reset_configuration!
|
|
30
|
+
@configuration = Configuration.new
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: creem
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Creem Contributors
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: net-http
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: rake
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '13.0'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '13.0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: rspec
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '3.12'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '3.12'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: rubocop
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '1.50'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '1.50'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: webmock
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '3.18'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '3.18'
|
|
82
|
+
description: Official Ruby SDK for Creem - a Merchant of Record platform for SaaS
|
|
83
|
+
and digital businesses. Manage products, checkouts, subscriptions, customers, transactions,
|
|
84
|
+
licenses, and discounts.
|
|
85
|
+
email:
|
|
86
|
+
- richard.sun@ai-firstly.com
|
|
87
|
+
executables: []
|
|
88
|
+
extensions: []
|
|
89
|
+
extra_rdoc_files: []
|
|
90
|
+
files:
|
|
91
|
+
- ".github/workflows/ci.yml"
|
|
92
|
+
- ".github/workflows/release.yml"
|
|
93
|
+
- ".gitignore"
|
|
94
|
+
- ".rspec"
|
|
95
|
+
- ".rubocop.yml"
|
|
96
|
+
- ".ruby-version"
|
|
97
|
+
- CHANGELOG.md
|
|
98
|
+
- CLAUDE.md
|
|
99
|
+
- Gemfile
|
|
100
|
+
- Gemfile.lock
|
|
101
|
+
- LICENSE
|
|
102
|
+
- Makefile
|
|
103
|
+
- README.md
|
|
104
|
+
- Rakefile
|
|
105
|
+
- creem.gemspec
|
|
106
|
+
- docs/api_reference.md
|
|
107
|
+
- docs/architecture.md
|
|
108
|
+
- docs/development.md
|
|
109
|
+
- docs/error_handling.md
|
|
110
|
+
- docs/getting_started.md
|
|
111
|
+
- docs/webhooks.md
|
|
112
|
+
- lib/creem.rb
|
|
113
|
+
- lib/creem/client.rb
|
|
114
|
+
- lib/creem/configuration.rb
|
|
115
|
+
- lib/creem/errors.rb
|
|
116
|
+
- lib/creem/resources/base.rb
|
|
117
|
+
- lib/creem/resources/checkouts.rb
|
|
118
|
+
- lib/creem/resources/customers.rb
|
|
119
|
+
- lib/creem/resources/discounts.rb
|
|
120
|
+
- lib/creem/resources/licenses.rb
|
|
121
|
+
- lib/creem/resources/products.rb
|
|
122
|
+
- lib/creem/resources/subscriptions.rb
|
|
123
|
+
- lib/creem/resources/transactions.rb
|
|
124
|
+
- lib/creem/version.rb
|
|
125
|
+
- lib/creem/webhook.rb
|
|
126
|
+
homepage: https://github.com/ai-firstly/creem-ruby
|
|
127
|
+
licenses:
|
|
128
|
+
- MIT
|
|
129
|
+
metadata:
|
|
130
|
+
allowed_push_host: https://rubygems.org
|
|
131
|
+
homepage_uri: https://github.com/ai-firstly/creem-ruby
|
|
132
|
+
source_code_uri: https://github.com/ai-firstly/creem-ruby
|
|
133
|
+
changelog_uri: https://github.com/ai-firstly/creem-ruby/blob/main/CHANGELOG.md
|
|
134
|
+
documentation_uri: https://rubydoc.info/gems/creem
|
|
135
|
+
bug_tracker_uri: https://github.com/ai-firstly/creem-ruby/issues
|
|
136
|
+
rubygems_mfa_required: 'true'
|
|
137
|
+
rdoc_options: []
|
|
138
|
+
require_paths:
|
|
139
|
+
- lib
|
|
140
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
141
|
+
requirements:
|
|
142
|
+
- - ">="
|
|
143
|
+
- !ruby/object:Gem::Version
|
|
144
|
+
version: 3.3.0
|
|
145
|
+
- - "<"
|
|
146
|
+
- !ruby/object:Gem::Version
|
|
147
|
+
version: '5.0'
|
|
148
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - ">="
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '0'
|
|
153
|
+
requirements: []
|
|
154
|
+
rubygems_version: 3.6.9
|
|
155
|
+
specification_version: 4
|
|
156
|
+
summary: Ruby SDK for the Creem payment platform API
|
|
157
|
+
test_files: []
|