abacatepay-ruby 1.1.0 → 1.2.2

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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -0
  3. data/CHANGELOG.md +137 -19
  4. data/README.md +43 -24
  5. data/abacatepay-ruby.gemspec +1 -1
  6. data/lib/abacate_pay/clients/billing_client.rb +2 -2
  7. data/lib/abacate_pay/clients/checkout_client.rb +1 -1
  8. data/lib/abacate_pay/clients/client.rb +66 -15
  9. data/lib/abacate_pay/clients/coupon_client.rb +4 -1
  10. data/lib/abacate_pay/clients/customer_client.rb +4 -1
  11. data/lib/abacate_pay/clients/payment_link_client.rb +2 -2
  12. data/lib/abacate_pay/clients/payout_client.rb +7 -1
  13. data/lib/abacate_pay/clients/pix_client.rb +11 -3
  14. data/lib/abacate_pay/clients/product_client.rb +4 -1
  15. data/lib/abacate_pay/clients/store_client.rb +3 -1
  16. data/lib/abacate_pay/clients/subscription_client.rb +5 -10
  17. data/lib/abacate_pay/clients/transparent_client.rb +4 -2
  18. data/lib/abacate_pay/clients/webhook_client.rb +21 -4
  19. data/lib/abacate_pay/clients.rb +1 -1
  20. data/lib/abacate_pay/configuration.rb +3 -3
  21. data/lib/abacate_pay/enums/billings/methods.rb +1 -1
  22. data/lib/abacate_pay/enums/checkouts/statuses.rb +4 -1
  23. data/lib/abacate_pay/enums/coupons/statuses.rb +4 -1
  24. data/lib/abacate_pay/enums/webhooks/event_types.rb +1 -1
  25. data/lib/abacate_pay/resources/coupons.rb +29 -3
  26. data/lib/abacate_pay/resources/customers.rb +62 -21
  27. data/lib/abacate_pay/resources/payouts.rb +6 -0
  28. data/lib/abacate_pay/resources/resource.rb +21 -5
  29. data/lib/abacate_pay/resources/transparents.rb +21 -4
  30. data/lib/abacate_pay/resources/webhook_endpoints.rb +1 -1
  31. data/lib/abacate_pay/resources.rb +1 -1
  32. data/lib/abacate_pay/version.rb +1 -1
  33. data/lib/abacate_pay/webhooks.rb +53 -7
  34. data/lib/abacatepay-ruby.rb +14 -0
  35. metadata +4 -3
@@ -32,7 +32,13 @@ module AbacatePay
32
32
  response = request("POST", "create", json: {
33
33
  amount: data.amount,
34
34
  externalId: data.external_id,
35
- description: data.description
35
+ description: data.description,
36
+ # The API nests the destination under `pix`, with
37
+ # `key` and `type`. Sending pixKey/pixKeyType at the
38
+ # top level fails with "Property 'pix' is missing";
39
+ # nesting the wrong names fails with
40
+ # "Property 'pix.type' is missing".
41
+ pix: { key: data.pix_key, type: data.pix_key_type }
36
42
  })
37
43
  Resources::Payouts.new(response)
38
44
  end
@@ -13,7 +13,11 @@ module AbacatePay
13
13
  super(URI, client)
14
14
  end
15
15
 
16
- # @param params [Hash] Optional pagination params (after, before, limit)
16
+ # The API requires an `id` on this endpoint: a bare call fails with
17
+ # "Expected property 'id' to be string but found: undefined". Despite the
18
+ # name it filters rather than lists.
19
+ #
20
+ # @param params [Hash] Params forwarded to the API; `id` is required
17
21
  # @return [Array<Resources::PixTransfers>]
18
22
  def list(**params)
19
23
  response = request("GET", "list", params: params.empty? ? nil : params)
@@ -37,8 +41,12 @@ module AbacatePay
37
41
  amount: data.amount,
38
42
  externalId: data.external_id,
39
43
  description: data.description,
40
- key: data.key,
41
- keyType: data.key_type
44
+ # The API nests the destination under `pix`, with
45
+ # `key` and `type`. Sending pixKey/pixKeyType at the
46
+ # top level fails with "Property 'pix' is missing";
47
+ # nesting the wrong names fails with
48
+ # "Property 'pix.type' is missing".
49
+ pix: { key: data.key, type: data.key_type }
42
50
  })
43
51
  Resources::PixTransfers.new(response)
44
52
  end
@@ -46,7 +46,10 @@ module AbacatePay
46
46
  # @param id [String] Product ID
47
47
  # @return [Resources::Products]
48
48
  def delete(id)
49
- response = request("POST", "delete", json: { id: id })
49
+ # The API reads the id from the query string on delete endpoints.
50
+ # Sending it only in the body fails with
51
+ # "Expected property 'id' to be string but found: undefined".
52
+ response = request("POST", "delete", params: { id: id }, json: {})
50
53
  Resources::Products.new(response)
51
54
  end
52
55
  end
@@ -12,7 +12,9 @@ module AbacatePay
12
12
 
13
13
  # @return [Resources::Store]
14
14
  def get
15
- response = request("GET", "store/get")
15
+ # The API serves this as `stores/get`, plural, even though the reference
16
+ # documents `store/get`. The singular path answers HTTP 400.
17
+ response = request("GET", "stores/get")
16
18
  Resources::Store.new(response)
17
19
  end
18
20
 
@@ -26,15 +26,10 @@ module AbacatePay
26
26
  methods: data.methods,
27
27
  externalId: data.external_id,
28
28
  customerId: data.customer&.id,
29
- items: data.products&.map do |product|
30
- {
31
- externalId: product.external_id,
32
- name: product.name,
33
- description: product.description,
34
- quantity: product.quantity,
35
- price: product.price
36
- }
37
- end
29
+ # The API expects the product id here, the same shape checkouts use.
30
+ # Sending externalId fails with
31
+ # "Expected property 'items.0.id' to be string".
32
+ items: data.products&.map { |product| { id: product.external_id, quantity: product.quantity } }
38
33
  }
39
34
 
40
35
  response = request("POST", "create", json: request_data)
@@ -52,7 +47,7 @@ module AbacatePay
52
47
  end
53
48
 
54
49
  # Changes the main product of an active subscription. The new price takes
55
- # effect on the next billing cycle the current cycle is untouched.
50
+ # effect on the next billing cycle, the current cycle is untouched.
56
51
  #
57
52
  # @param id [String] The subscription ID (`subs_...`)
58
53
  # @param product_id [String] The new product ID (`prod_...`), which must have a cycle
@@ -45,12 +45,14 @@ module AbacatePay
45
45
  # @param id [String] QR code ID (dev mode only)
46
46
  # @return [Resources::Transparents]
47
47
  def simulate_payment(id)
48
- response = request("POST", "simulate-payment", json: { id: id })
48
+ # The API reads the id from the query string here, like #check. Sending
49
+ # it only in the body fails with "Expected property 'id'".
50
+ response = request("POST", "simulate-payment", params: { id: id }, json: {})
49
51
  Resources::Transparents.new(response)
50
52
  end
51
53
 
52
54
  # Refunds a transparent payment in full. AbacatePay does not support
53
- # partial refunds the original amount is always returned.
55
+ # partial refunds, the original amount is always returned.
54
56
  #
55
57
  # @param id [String] Public charge ID (`pix_char_...`, `card_...`, `char_...`)
56
58
  # @return [Resources::Transparents] The refunded charge
@@ -11,6 +11,9 @@ module AbacatePay
11
11
  class WebhookClient < Client
12
12
  URI = "webhooks"
13
13
 
14
+ # Shortest signing secret the API accepts.
15
+ MINIMUM_SECRET_LENGTH = 32
16
+
14
17
  # @param client [Faraday::Connection, nil] Optional Faraday client
15
18
  def initialize(client = nil)
16
19
  super(URI, client)
@@ -32,7 +35,7 @@ module AbacatePay
32
35
 
33
36
  # Registers a new webhook endpoint.
34
37
  #
35
- # The secret is what AbacatePay signs deliveries with pass the same
38
+ # The secret is what AbacatePay signs deliveries with, pass the same
36
39
  # value to {AbacatePay::Webhooks.construct_event} when handling them.
37
40
  #
38
41
  # @param name [String] Identifying name
@@ -40,11 +43,19 @@ module AbacatePay
40
43
  # @param secret [String] Signing secret
41
44
  # @param events [Array<String>] Event types to subscribe to
42
45
  # @return [Resources::WebhookEndpoints] The created webhook
43
- # @raise [ArgumentError] if the endpoint is not an HTTPS URL
46
+ # @raise [ArgumentError] if the endpoint is not HTTPS, the event list is
47
+ # empty, or the secret is shorter than the API accepts
44
48
  def create(name:, endpoint:, secret:, events:)
45
49
  raise ArgumentError, "endpoint must be an HTTPS URL, got #{endpoint.inspect}" unless https_url?(endpoint)
46
50
  raise ArgumentError, "events must not be empty" if Array(events).empty?
47
51
 
52
+ # The API rejects anything shorter with
53
+ # "Expected string length greater or equal to 32".
54
+ if secret.to_s.length < MINIMUM_SECRET_LENGTH
55
+ raise ArgumentError,
56
+ "secret must be at least #{MINIMUM_SECRET_LENGTH} characters, got #{secret.to_s.length}"
57
+ end
58
+
48
59
  response = request("POST", "create", json: {
49
60
  name: name,
50
61
  endpoint: endpoint,
@@ -55,9 +66,15 @@ module AbacatePay
55
66
  end
56
67
 
57
68
  # @param id [String] The webhook ID
58
- # @return [Resources::WebhookEndpoints] The deleted webhook
69
+ # @return [Resources::WebhookEndpoints, nil] The deleted webhook, or nil
70
+ # when the API confirms the deletion without echoing the object
59
71
  def delete(id)
60
- response = request("POST", "delete", json: { id: id })
72
+ # The API reads the id from the query string here, like
73
+ # transparents/simulate-payment. Sending it in the body fails with
74
+ # "Expected property 'id' to be string but found: undefined".
75
+ response = request("POST", "delete", params: { id: id }, json: {})
76
+ return nil if response.nil?
77
+
61
78
  Resources::WebhookEndpoints.new(response)
62
79
  end
63
80
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Client must load first every other client inherits from it.
3
+ # Client must load first: every other client inherits from it.
4
4
  require "abacate_pay/clients/client"
5
5
 
6
6
  require "abacate_pay/clients/billing_client"
@@ -9,8 +9,8 @@ module AbacatePay
9
9
  # @api public
10
10
  class Configuration
11
11
  # The only base URL this SDK speaks. v1 still exists, but under a
12
- # different dialect singular paths (`/v1/billing/`, `/v1/customer/`) and
13
- # different resource names (`pixQrCode`) which this SDK has never
12
+ # different dialect, singular paths (`/v1/billing/`, `/v1/customer/`) and
13
+ # different resource names (`pixQrCode`), which this SDK has never
14
14
  # implemented. Deriving a base URL from the token prefix only produced 404s
15
15
  # against v1 while sending v2-shaped paths.
16
16
  API_BASE_URL = "https://api.abacatepay.com/v2"
@@ -43,7 +43,7 @@ module AbacatePay
43
43
  @api_token = nil
44
44
  end
45
45
 
46
- # @deprecated The environment is determined by the API key itself keys
46
+ # @deprecated The environment is determined by the API key itself, keys
47
47
  # created in Dev mode produce simulated transactions, production keys
48
48
  # produce real ones. This setting has never had any effect and is kept
49
49
  # only so existing initializers keep loading.
@@ -14,7 +14,7 @@ module AbacatePay
14
14
  # @return [String] Credit card payment
15
15
  CARD = "CARD"
16
16
 
17
- # Boleto bancário. Supports a due date and late-payment interest/fine
17
+ # Boleto bancário. Supports a due date and late-payment interest/fine -
18
18
  # see Resources::Checkouts#due_date, #interest and #fine.
19
19
  # @return [String] Boleto payment method
20
20
  BOLETO = "BOLETO"
@@ -10,8 +10,11 @@ module AbacatePay
10
10
  PAID = "PAID"
11
11
  REFUNDED = "REFUNDED"
12
12
 
13
+ # Reusable payment links are created ACTIVE rather than PENDING.
14
+ ACTIVE = "ACTIVE"
15
+
13
16
  def self.values
14
- [PENDING, EXPIRED, CANCELLED, PAID, REFUNDED]
17
+ [PENDING, EXPIRED, CANCELLED, PAID, REFUNDED, ACTIVE]
15
18
  end
16
19
 
17
20
  def self.valid?(value)
@@ -8,8 +8,11 @@ module AbacatePay
8
8
  INACTIVE = "INACTIVE"
9
9
  EXPIRED = "EXPIRED"
10
10
 
11
+ # What the API returns for a coupon turned off through `toggle`.
12
+ DISABLED = "DISABLED"
13
+
11
14
  def self.values
12
- [ACTIVE, INACTIVE, EXPIRED]
15
+ [ACTIVE, INACTIVE, EXPIRED, DISABLED]
13
16
  end
14
17
 
15
18
  def self.valid?(value)
@@ -14,7 +14,7 @@ module AbacatePay
14
14
  SUBSCRIPTION_RENEWED = "subscription.renewed"
15
15
  SUBSCRIPTION_CANCELLED = "subscription.cancelled"
16
16
 
17
- # Recurring charge failed the dunning signal. Without handling this,
17
+ # Recurring charge failed, the dunning signal. Without handling this,
18
18
  # a failing subscription looks identical to a healthy one.
19
19
  SUBSCRIPTION_PAYMENT_FAILED = "subscription.payment_failed"
20
20
 
@@ -11,13 +11,38 @@ module AbacatePay
11
11
 
12
12
  DATETIME_PROPERTIES = %w[created_at updated_at].freeze
13
13
 
14
- attr_reader :id, :code, :discount, :discount_kind, :max_redeems,
15
- :current_redeems, :status, :created_at, :updated_at
14
+ attr_reader :id, :discount, :discount_kind, :max_redeems,
15
+ :status, :notes, :dev_mode, :created_at, :updated_at
16
+
17
+ # @return [Integer, nil] Times the coupon has been redeemed
18
+ attr_reader :redeems_count
16
19
 
17
20
  def initialize(data)
18
21
  fill(data)
19
22
  end
20
23
 
24
+ # The coupon code.
25
+ #
26
+ # The API uses the code as the object's `id` and sends no separate
27
+ # `code` field, so this reader was always nil for API data.
28
+ #
29
+ # @return [String, nil]
30
+ def code
31
+ @code || @id
32
+ end
33
+
34
+ # @return [Integer, nil] Times the coupon has been redeemed
35
+ #
36
+ # @deprecated The API calls this `redeemsCount`; use {#redeems_count}.
37
+ def current_redeems
38
+ @current_redeems || @redeems_count
39
+ end
40
+
41
+ # @return [Boolean, nil] Whether the coupon belongs to Dev mode
42
+ def dev_mode?
43
+ @dev_mode
44
+ end
45
+
21
46
  private
22
47
 
23
48
  def process_value(property, value)
@@ -35,7 +60,8 @@ module AbacatePay
35
60
  protected
36
61
 
37
62
  attr_writer :id, :code, :discount, :discount_kind, :max_redeems,
38
- :current_redeems, :status, :created_at, :updated_at
63
+ :current_redeems, :redeems_count, :status, :notes,
64
+ :dev_mode, :created_at, :updated_at
39
65
  end
40
66
  end
41
67
  end
@@ -2,45 +2,86 @@
2
2
 
3
3
  module AbacatePay
4
4
  module Resources
5
- # Represents a customer resource in the AbacatePay payment system.
5
+ # Represents a customer in the AbacatePay system.
6
6
  #
7
- # This class handles customer data including identification and metadata,
8
- # providing a structured way to manage customer information within the system.
7
+ # The API returns the customer fields at the top level of the object:
8
+ #
9
+ # { "id": "cust_...", "name": "Ana", "email": "ana@example.com",
10
+ # "cellphone": "...", "taxId": "...", "metadata": {} }
11
+ #
12
+ # Earlier versions of this class only mapped `id` and a nested `metadata`,
13
+ # so every other field was silently dropped and `customer.metadata.name`
14
+ # came back nil for real API data.
15
+ #
16
+ # Both shapes work now: the fields are exposed directly, and `metadata`
17
+ # keeps answering for code written against the previous interface.
9
18
  class Customers < Resource
10
- # Maps property names to their corresponding resource classes
11
19
  RESOURCE_PROPERTIES = {
12
20
  metadata: "AbacatePay::Resources::Customers::Metadata"
13
21
  }.freeze
14
22
 
15
- # @return [String, nil] The unique identifier for the customer
16
- attr_reader :id
23
+ # Fields the API sends inside the customer object.
24
+ IDENTITY_FIELDS = %i[name email cellphone tax_id].freeze
17
25
 
18
- # @return [Metadata, nil] Additional customer information
19
- attr_reader :metadata
26
+ attr_reader :id, :country, :zip_code, :dev_mode
20
27
 
21
- # Creates a new Customer instance
22
- #
23
- # @param data [Hash] The raw customer data
24
- # @raise [ArgumentError] If the data is invalid
28
+ # @return [String, nil] Customer's name
29
+ attr_reader :name
30
+
31
+ # @return [String, nil] Customer's email address
32
+ attr_reader :email
33
+
34
+ # @return [String, nil] Customer's cellphone number
35
+ attr_reader :cellphone
36
+
37
+ # @return [String, nil] Customer's tax identification number
38
+ attr_reader :tax_id
39
+
40
+ # @param data [Hash] The customer properties
25
41
  def initialize(data)
26
42
  fill(data)
27
43
  end
28
44
 
29
- private
45
+ # @return [Boolean, nil] Whether this customer belongs to Dev mode
46
+ def dev_mode?
47
+ @dev_mode
48
+ end
30
49
 
31
- # Process a value based on its property
50
+ # The identity fields, wrapped.
32
51
  #
52
+ # Kept because `customer.metadata.name` is what the README documented and
53
+ # what existing integrations call. When the API sends the fields at the
54
+ # top level, this builds the wrapper from them rather than returning the
55
+ # empty object the API puts in `metadata`.
56
+ #
57
+ # @return [Customers::Metadata, nil]
58
+ def metadata
59
+ return @metadata if metadata_populated?(@metadata)
60
+
61
+ identity = IDENTITY_FIELDS.to_h { |field| [field, public_send(field)] }.compact
62
+ return @metadata if identity.empty?
63
+
64
+ Customers::Metadata.new(identity)
65
+ end
66
+
67
+ private
68
+
69
+ # @param metadata [Customers::Metadata, nil]
70
+ # @return [Boolean] Whether the API actually filled the nested object
71
+ def metadata_populated?(metadata)
72
+ return false if metadata.nil?
73
+
74
+ IDENTITY_FIELDS.any? { |field| metadata.public_send(field) }
75
+ end
76
+
33
77
  # @param property [String] The property name
34
- # @param value [Object] The value to process
78
+ # @param value [Object] The raw value
35
79
  # @return [Object] The processed value
36
80
  def process_value(property, value)
37
81
  return nil if value.nil?
38
82
 
39
83
  if RESOURCE_PROPERTIES.key?(property.to_sym)
40
- initialize_resource(
41
- Object.const_get(RESOURCE_PROPERTIES[property.to_sym]),
42
- value
43
- )
84
+ initialize_resource(Object.const_get(RESOURCE_PROPERTIES[property.to_sym]), value)
44
85
  else
45
86
  value
46
87
  end
@@ -48,8 +89,8 @@ module AbacatePay
48
89
 
49
90
  protected
50
91
 
51
- # @!visibility private
52
- attr_writer :id, :metadata
92
+ attr_writer :id, :metadata, :name, :email, :cellphone, :tax_id,
93
+ :country, :zip_code, :dev_mode
53
94
  end
54
95
  end
55
96
  end
@@ -10,6 +10,12 @@ module AbacatePay
10
10
 
11
11
  DATETIME_PROPERTIES = %w[created_at updated_at].freeze
12
12
 
13
+ # @return [String, nil] Destination PIX key
14
+ attr_accessor :pix_key
15
+
16
+ # @return [String, nil] Destination PIX key type
17
+ attr_accessor :pix_key_type
18
+
13
19
  attr_reader :id, :amount, :external_id, :description,
14
20
  :status, :created_at, :updated_at
15
21
 
@@ -21,16 +21,28 @@ module AbacatePay
21
21
  raise ArgumentError, "Invalid datetime value: #{value}"
22
22
  end
23
23
 
24
- # Initialize an enum from a string or enum object
24
+ # Initialize an enum from a string or enum object.
25
+ #
26
+ # Unknown values pass through with a warning rather than raising. This
27
+ # method runs while parsing API responses, and AbacatePay adds statuses
28
+ # over time: rejecting an unrecognised one would turn every new value
29
+ # into a crash inside `list` and `get` for every integration at once.
30
+ # That happened with the coupon status `DISABLED` and the payment-link
31
+ # status `ACTIVE`, neither of which the SDK knew about.
32
+ #
33
+ # Use {AbacatePay::Enums} `validate!` directly when you want a hard
34
+ # failure on a value you are about to send.
25
35
  #
26
36
  # @param enum_class [Class] The enum class to initialize
27
37
  # @param value [String, Object] The value to initialize
28
- # @return [Object, nil] The initialized enum or nil
29
- # @raise [ArgumentError] If the value is invalid
38
+ # @return [Object, nil] The value, validated when known
30
39
  def initialize_enum(enum_class, value)
31
40
  return nil if value.nil? || value.empty?
41
+ return value if enum_class.valid?(value)
32
42
 
33
- enum_class.validate!(value)
43
+ warn "[AbacatePay] unknown #{enum_class.name.split("::").last} value #{value.inspect}. " \
44
+ "Passing it through; upgrade the gem if this is a new API value."
45
+ value
34
46
  end
35
47
 
36
48
  # Initialize a resource from a hash or resource object
@@ -51,7 +63,7 @@ module AbacatePay
51
63
  resource_class.new(value)
52
64
  end
53
65
 
54
- # Default value processor returns the value as-is.
66
+ # Default value processor, returns the value as-is.
55
67
  # Subclasses override this to handle enums, datetimes, and nested resources.
56
68
  #
57
69
  # @param _property [String] The property name
@@ -66,6 +78,10 @@ module AbacatePay
66
78
  # @param data [Hash] The data to fill with
67
79
  # @return [void]
68
80
  def fill(data)
81
+ # Some endpoints answer a successful call with no payload, so the
82
+ # resource is built from nil. An empty object beats a NoMethodError.
83
+ return if data.nil?
84
+
69
85
  data.each do |key, value|
70
86
  property = camel_to_snake(key)
71
87
  next unless respond_to?("#{property}=", true)
@@ -10,19 +10,36 @@ module AbacatePay
10
10
 
11
11
  DATETIME_PROPERTIES = %w[created_at updated_at expires_at].freeze
12
12
 
13
+ # qr_code and qr_code_image are defined below rather than generated here:
14
+ # they fall back to the br_code fields the API actually sends.
13
15
  attr_reader :id, :amount, :status, :method, :description,
14
- :expires_in, :qr_code, :qr_code_image, :customer,
16
+ :expires_in, :customer,
15
17
  :metadata, :dev_mode, :created_at, :updated_at,
16
18
  # Boleto: due date sent on create, plus the payment slip the
17
- # API returns digitable line, viewing URL, and the PIX
19
+ # API returns: digitable line, viewing URL, and the PIX
18
20
  # fallback issued for the same charge.
19
21
  :due_date, :bar_code, :url, :br_code, :br_code_base64,
20
- :expires_at
22
+ :expires_at, :platform_fee, :receipt_url
21
23
 
22
24
  def initialize(data)
23
25
  fill(data)
24
26
  end
25
27
 
28
+ # The API returns the copy-and-paste payload as `brCode` and the image as
29
+ # `brCodeBase64`. Older documentation used `qrCode`/`qrCodeImage`, so both
30
+ # spellings are accepted: the reader prefers the `qr*` value when the API
31
+ # sends one and falls back to `br*`.
32
+ #
33
+ # @return [String, nil] PIX copy-and-paste payload
34
+ def qr_code
35
+ @qr_code || br_code
36
+ end
37
+
38
+ # @return [String, nil] PIX QR code image as a data URI
39
+ def qr_code_image
40
+ @qr_code_image || br_code_base64
41
+ end
42
+
26
43
  def dev_mode?
27
44
  @dev_mode
28
45
  end
@@ -47,7 +64,7 @@ module AbacatePay
47
64
  :expires_in, :qr_code, :qr_code_image, :customer,
48
65
  :metadata, :dev_mode, :created_at, :updated_at,
49
66
  :due_date, :bar_code, :url, :br_code, :br_code_base64,
50
- :expires_at
67
+ :expires_at, :platform_fee, :receipt_url
51
68
  end
52
69
  end
53
70
  end
@@ -4,7 +4,7 @@ module AbacatePay
4
4
  module Resources
5
5
  # Represents a registered webhook endpoint in the AbacatePay system.
6
6
  #
7
- # This is the endpoint *registration* the URL AbacatePay delivers events
7
+ # This is the endpoint *registration*, the URL AbacatePay delivers events
8
8
  # to. For verifying and parsing an inbound delivery, see {AbacatePay::Webhooks}.
9
9
  class WebhookEndpoints < Resource
10
10
  # @return [String, nil] Webhook ID
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Resource must load first every other resource inherits from it.
3
+ # Resource must load first: every other resource inherits from it.
4
4
  require "abacate_pay/resources/resource"
5
5
 
6
6
  require "abacate_pay/resources/billings"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AbacatePay
4
- VERSION = "1.1.0"
4
+ VERSION = "1.2.2"
5
5
  end