abacatepay-ruby 0.1.0 → 1.0.0
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/.rubocop.yml +125 -0
- data/CHANGELOG.md +121 -1
- data/README.md +408 -87
- data/Rakefile +1 -1
- data/abacatepay-ruby.gemspec +16 -10
- data/lib/abacate_pay/clients/billing_client.rb +80 -0
- data/lib/abacate_pay/clients/checkout_client.rb +70 -0
- data/lib/{abacatepay → abacate_pay}/clients/client.rb +20 -7
- data/lib/abacate_pay/clients/coupon_client.rb +57 -0
- data/lib/abacate_pay/clients/customer_client.rb +58 -0
- data/lib/abacate_pay/clients/payment_link_client.rb +71 -0
- data/lib/abacate_pay/clients/payout_client.rb +41 -0
- data/lib/abacate_pay/clients/pix_client.rb +47 -0
- data/lib/abacate_pay/clients/product_client.rb +54 -0
- data/lib/abacate_pay/clients/store_client.rb +40 -0
- data/lib/abacate_pay/clients/subscription_client.rb +55 -0
- data/lib/abacate_pay/clients/transparent_client.rb +73 -0
- data/lib/abacate_pay/clients/webhook_client.rb +82 -0
- data/lib/abacate_pay/clients.rb +24 -0
- data/lib/abacate_pay/configuration.rb +67 -0
- data/lib/{abacatepay/enums/billing → abacate_pay/enums/billings}/frequencies.rb +9 -3
- data/lib/{abacatepay/enums/billing → abacate_pay/enums/billings}/methods.rb +5 -3
- data/lib/{abacatepay/enums/billing → abacate_pay/enums/billings}/statuses.rb +3 -2
- data/lib/abacate_pay/enums/checkouts/statuses.rb +29 -0
- data/lib/abacate_pay/enums/coupons/discount_kinds.rb +26 -0
- data/lib/abacate_pay/enums/coupons/statuses.rb +27 -0
- data/lib/abacate_pay/enums/payouts/statuses.rb +29 -0
- data/lib/abacate_pay/enums/pix/key_types.rb +30 -0
- data/lib/abacate_pay/enums/products/cycles.rb +28 -0
- data/lib/abacate_pay/enums/transfers/statuses.rb +30 -0
- data/lib/abacate_pay/enums/webhooks/event_types.rb +43 -0
- data/lib/abacate_pay/enums.rb +20 -0
- data/lib/{abacatepay/resources/billing → abacate_pay/resources/billings}/metadata.rb +2 -8
- data/lib/{abacatepay/resources/billing → abacate_pay/resources/billings}/product.rb +2 -8
- data/lib/{abacatepay/resources/billing.rb → abacate_pay/resources/billings.rb} +16 -16
- data/lib/abacate_pay/resources/checkouts.rb +76 -0
- data/lib/abacate_pay/resources/coupons.rb +41 -0
- data/lib/{abacatepay/resources/customer → abacate_pay/resources/customers}/metadata.rb +2 -8
- data/lib/{abacatepay/resources/customer.rb → abacate_pay/resources/customers.rb} +5 -5
- data/lib/abacate_pay/resources/payouts.rb +40 -0
- data/lib/abacate_pay/resources/pix_transfers.rb +41 -0
- data/lib/abacate_pay/resources/products.rb +40 -0
- data/lib/{abacatepay → abacate_pay}/resources/resource.rb +33 -21
- data/lib/abacate_pay/resources/store/balance.rb +20 -0
- data/lib/abacate_pay/resources/store.rb +36 -0
- data/lib/abacate_pay/resources/subscriptions.rb +72 -0
- data/lib/abacate_pay/resources/transparents.rb +46 -0
- data/lib/abacate_pay/resources/webhook_endpoints.rb +49 -0
- data/lib/abacate_pay/resources.rb +27 -0
- data/lib/{abacatepay → abacate_pay}/version.rb +2 -2
- data/lib/abacate_pay/webhooks/event.rb +20 -0
- data/lib/abacate_pay/webhooks.rb +100 -0
- data/lib/abacate_pay.rb +111 -4
- metadata +69 -56
- data/lib/abacatepay/clients/billing_client.rb +0 -60
- data/lib/abacatepay/clients/customer_client.rb +0 -39
- data/lib/abacatepay/clients.rb +0 -12
- data/lib/abacatepay/configuration.rb +0 -56
- data/lib/abacatepay/enums.rb +0 -12
- data/lib/abacatepay/resources.rb +0 -15
- data/sig/abacatepay/rails.rbs +0 -6
data/README.md
CHANGED
|
@@ -1,121 +1,239 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# AbacatePay Ruby SDK
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
SDK oficial da **AbacatePay** para integrar pagamentos via **PIX** de forma simples, segura e idiomática em Ruby.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
gem 'abacatepay-ruby'
|
|
9
|
-
```
|
|
7
|
+
O [`abacatepay-ruby`](https://rubygems.org/gems/abacatepay-ruby) é um **wrapper versionado de alto nível** sobre a API da AbacatePay, focado em **DX**, **verificação segura de webhooks** e **erros tipados**.
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
<img src="https://res.cloudinary.com/dkok1obj5/image/upload/v1767631413/avo_clhmaf.png" width="100%" alt="AbacatePay Open Source"/>
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
bundle install
|
|
15
|
-
```
|
|
11
|
+
Funciona em qualquer aplicação Ruby — Rails, Sinatra, Hanami ou Ruby puro.
|
|
16
12
|
|
|
17
|
-
|
|
13
|
+
Referência completa da API [aqui](https://abacatepay.readme.io/reference).
|
|
14
|
+
|
|
15
|
+
## Requisitos
|
|
16
|
+
|
|
17
|
+
Ruby **3.2 ou superior**. Testado em 3.2, 3.3, 3.4 e 4.0.
|
|
18
|
+
|
|
19
|
+
## Instalação
|
|
20
|
+
|
|
21
|
+
</div>
|
|
18
22
|
|
|
19
23
|
```bash
|
|
20
|
-
|
|
24
|
+
bundle add abacatepay-ruby
|
|
21
25
|
```
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
<div align="center">
|
|
28
|
+
|
|
29
|
+
Ou adicione ao seu `Gemfile`:
|
|
24
30
|
|
|
25
|
-
|
|
31
|
+
</div>
|
|
26
32
|
|
|
27
33
|
```ruby
|
|
28
|
-
|
|
29
|
-
AbacatePay.configure do |config|
|
|
30
|
-
config.api_token = ENV['ABACATEPAY_TOKEN']
|
|
31
|
-
config.environment = :sandbox # or :production
|
|
32
|
-
end
|
|
34
|
+
gem 'abacatepay-ruby'
|
|
33
35
|
```
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
<div align="center">
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
## Uso básico
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
</div>
|
|
40
42
|
|
|
41
43
|
```ruby
|
|
42
|
-
|
|
44
|
+
AbacatePay.configure do |config|
|
|
45
|
+
config.api_token = ENV['ABACATEPAY_TOKEN']
|
|
46
|
+
config.timeout = 30 # opcional, em segundos
|
|
47
|
+
end
|
|
43
48
|
```
|
|
44
49
|
|
|
45
|
-
|
|
50
|
+
<div align="center">
|
|
46
51
|
|
|
47
|
-
|
|
52
|
+
Nunca utilize sua API key diretamente no código.
|
|
53
|
+
**Sempre use variáveis de ambiente**.
|
|
48
54
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
Em Rails, coloque isso em `config/initializers/abacatepay.rb`.
|
|
56
|
+
|
|
57
|
+
Trocar o token em runtime tem efeito imediato — os clients são reconstruídos a cada `configure`.
|
|
52
58
|
|
|
53
|
-
|
|
59
|
+
### Criando uma cobrança
|
|
54
60
|
|
|
55
|
-
|
|
61
|
+
</div>
|
|
56
62
|
|
|
57
63
|
```ruby
|
|
58
|
-
|
|
59
|
-
AbacatePay::Resources::
|
|
60
|
-
frequency:
|
|
61
|
-
methods: [
|
|
64
|
+
checkout = AbacatePay.checkouts.create(
|
|
65
|
+
AbacatePay::Resources::Checkouts.new(
|
|
66
|
+
frequency: 'ONE_TIME',
|
|
67
|
+
methods: ['PIX'],
|
|
62
68
|
products: [
|
|
63
|
-
AbacatePay::Resources::
|
|
64
|
-
external_id: '
|
|
69
|
+
AbacatePay::Resources::Billings::Product.new(
|
|
70
|
+
external_id: 'prod_123',
|
|
65
71
|
name: 'Product A',
|
|
66
|
-
description: 'Description of product A',
|
|
67
72
|
quantity: 1,
|
|
68
|
-
price: 100
|
|
73
|
+
price: 100
|
|
69
74
|
)
|
|
70
75
|
],
|
|
71
|
-
|
|
72
|
-
return_url: 'https://www.abacatepay.com',
|
|
73
|
-
completion_url: 'https://www.abacatepay.com'
|
|
74
|
-
),
|
|
75
|
-
customer: AbacatePay::Resources::Customer.new(
|
|
76
|
-
metadata: AbacatePay::Resources::Customer::Metadata.new(
|
|
77
|
-
name: 'Abacate Lover',
|
|
78
|
-
cellphone: '01912341234',
|
|
79
|
-
email: 'lover@abacate.com',
|
|
80
|
-
tax_id: '13827826837'
|
|
81
|
-
)
|
|
82
|
-
)
|
|
76
|
+
customer: AbacatePay::Resources::Customers.new(id: 'cust_123')
|
|
83
77
|
)
|
|
84
78
|
)
|
|
85
79
|
```
|
|
86
80
|
|
|
87
|
-
|
|
81
|
+
<div align="center">
|
|
82
|
+
|
|
83
|
+
### Procure por alguns clientes
|
|
84
|
+
|
|
85
|
+
</div>
|
|
88
86
|
|
|
89
87
|
```ruby
|
|
90
|
-
AbacatePay
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
customers = AbacatePay.customers.list(limit: 25)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
<div align="center">
|
|
92
|
+
|
|
93
|
+
Todos os métodos `list` aceitam parâmetros de paginação e filtro opcionais:
|
|
94
|
+
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
AbacatePay.customers.list(limit: 10, after: 'cursor_abc')
|
|
99
|
+
AbacatePay.checkouts.list(status: 'PAID', email: 'user@example.com')
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
<div align="center">
|
|
103
|
+
|
|
104
|
+
## Versionamento
|
|
105
|
+
|
|
106
|
+
O SDK fala **exclusivamente a v2** — `https://api.abacatepay.com/v2`. A v1 foi desligada pela AbacatePay e responde `{"error":"Not found"}` em toda rota, então não há o que negociar.
|
|
107
|
+
|
|
108
|
+
O ambiente (dev mode x produção) é definido **pela chave de API**, não por configuração: chaves de Dev mode geram transações simuladas. Por isso `config.environment` não faz nada — ela continua aceita para não quebrar initializers existentes, mas emite aviso de depreciação.
|
|
109
|
+
|
|
110
|
+
O `BillingClient` também está descontinuado, substituído pelo `CheckoutClient`. Ele emite um aviso ao ser instanciado, e seus endpoints `/billings/*` não existem na v2:
|
|
111
|
+
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
[DEPRECATION] BillingClient is deprecated. Use CheckoutClient instead.
|
|
93
116
|
```
|
|
94
117
|
|
|
95
|
-
|
|
118
|
+
<div align="center">
|
|
96
119
|
|
|
97
|
-
|
|
120
|
+
## Tratamento de erros
|
|
121
|
+
|
|
122
|
+
Diferente do SDK de Node, **este SDK levanta exceções** — ele não retorna `{ data, error, success }`. Toda falha vira uma exceção tipada que herda de `AbacatePay::Error`, então você pode capturar tudo de uma vez ou tratar caso a caso.
|
|
123
|
+
|
|
124
|
+
</div>
|
|
98
125
|
|
|
99
126
|
```ruby
|
|
100
|
-
|
|
127
|
+
begin
|
|
128
|
+
checkout = AbacatePay.checkouts.create(data)
|
|
129
|
+
rescue AbacatePay::ConfigurationError => e
|
|
130
|
+
# token ausente ou vazio
|
|
131
|
+
rescue AbacatePay::ApiError => e
|
|
132
|
+
# a API recusou a chamada, ou houve falha de rede/timeout
|
|
133
|
+
Rails.logger.error(e.message)
|
|
134
|
+
end
|
|
101
135
|
```
|
|
102
136
|
|
|
103
|
-
|
|
137
|
+
<div align="center">
|
|
138
|
+
|
|
139
|
+
| Exceção | Quando acontece |
|
|
140
|
+
|---|---|
|
|
141
|
+
| `AbacatePay::ConfigurationError` | Token ausente ou vazio |
|
|
142
|
+
| `AbacatePay::ApiError` | Erro da API, falha de rede ou timeout |
|
|
143
|
+
| `AbacatePay::Webhooks::SignatureError` | Assinatura de webhook ausente, vazia ou inválida |
|
|
144
|
+
| `AbacatePay::Webhooks::PayloadError` | Corpo do webhook malformado ou que não é um objeto JSON |
|
|
145
|
+
|
|
146
|
+
Erros de rede e timeout são normalizados para `ApiError`, com a mensagem da API preservada quando ela envia uma.
|
|
147
|
+
|
|
148
|
+
## Webhooks
|
|
104
149
|
|
|
105
|
-
|
|
150
|
+
Endpoints de webhook são públicos e não autenticados. Use `construct_event`, que **verifica a assinatura antes de fazer o parse** — é o único ponto de entrada que não permite agir sobre um payload não verificado.
|
|
151
|
+
|
|
152
|
+
</div>
|
|
106
153
|
|
|
107
154
|
```ruby
|
|
108
|
-
|
|
155
|
+
payload = request.body.read
|
|
156
|
+
signature = request.headers['X-Webhook-Signature']
|
|
157
|
+
secret = ENV['ABACATEPAY_WEBHOOK_SECRET']
|
|
158
|
+
|
|
159
|
+
begin
|
|
160
|
+
event = AbacatePay::Webhooks.construct_event(
|
|
161
|
+
payload: payload, signature: signature, secret: secret
|
|
162
|
+
)
|
|
163
|
+
rescue AbacatePay::Webhooks::SignatureError
|
|
164
|
+
return head :unauthorized
|
|
165
|
+
rescue AbacatePay::Webhooks::PayloadError
|
|
166
|
+
return head :bad_request
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
case event.type
|
|
170
|
+
when 'checkout.completed' then handle_payment(event.data)
|
|
171
|
+
when 'checkout.refunded' then handle_refund(event.data)
|
|
172
|
+
when 'subscription.renewed' then handle_renewal(event.data)
|
|
173
|
+
end
|
|
109
174
|
```
|
|
110
175
|
|
|
111
|
-
|
|
176
|
+
<div align="center">
|
|
177
|
+
|
|
178
|
+
Header ausente, secret vazio, assinatura forjada e corpo malformado são todos tratados como casos esperados — levantam erro tipado em vez de derrubar o endpoint. A comparação de assinatura é feita em tempo constante.
|
|
179
|
+
|
|
180
|
+
Os métodos de baixo nível continuam disponíveis:
|
|
112
181
|
|
|
113
|
-
|
|
182
|
+
</div>
|
|
114
183
|
|
|
115
184
|
```ruby
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
185
|
+
# Levanta SignatureError se a assinatura estiver ausente ou inválida
|
|
186
|
+
AbacatePay::Webhooks.verify!(payload: payload, signature: signature, secret: secret)
|
|
187
|
+
|
|
188
|
+
# Contraparte booleana — nunca levanta exceção
|
|
189
|
+
AbacatePay::Webhooks.valid?(payload: payload, signature: signature, secret: secret)
|
|
190
|
+
|
|
191
|
+
# Faz parse de um corpo já verificado
|
|
192
|
+
AbacatePay::Webhooks.parse(payload)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
<div align="center">
|
|
196
|
+
|
|
197
|
+
### Eventos disponíveis
|
|
198
|
+
|
|
199
|
+
| Categoria | Eventos |
|
|
200
|
+
|---|---|
|
|
201
|
+
| Checkout | `checkout.completed`, `checkout.refunded`, `checkout.disputed` |
|
|
202
|
+
| Transparent | `transparent.completed`, `transparent.refunded`, `transparent.disputed` |
|
|
203
|
+
| Subscription | `subscription.completed`, `subscription.renewed`, `subscription.cancelled` |
|
|
204
|
+
| Transfer | `transfer.completed`, `transfer.failed` |
|
|
205
|
+
| Payout | `payout.completed`, `payout.failed` |
|
|
206
|
+
|
|
207
|
+
## Recursos
|
|
208
|
+
|
|
209
|
+
Todos os recursos são acessíveis pela fachada `AbacatePay.<recurso>`.
|
|
210
|
+
|
|
211
|
+
| Recurso | Métodos |
|
|
212
|
+
|---|---|
|
|
213
|
+
| `customers` | `list` `get` `create` `delete` |
|
|
214
|
+
| `products` | `list` `get` `create` `delete` |
|
|
215
|
+
| `coupons` | `list` `get` `create` `delete` `toggle` |
|
|
216
|
+
| `checkouts` | `list` `get` `create` `refund` |
|
|
217
|
+
| `subscriptions` | `list` `create` `cancel` |
|
|
218
|
+
| `transparents` | `list` `create` `check` `simulate_payment` `refund` |
|
|
219
|
+
| `pix` | `list` `get` `send_pix` |
|
|
220
|
+
| `payouts` | `list` `get` `create` |
|
|
221
|
+
| `store` | `get` `merchant_info` `mrr` `revenue` |
|
|
222
|
+
| `payment_links` | `list` `get` `create` `refund` |
|
|
223
|
+
| `webhook_endpoints` | `list` `get` `create` `delete` |
|
|
224
|
+
|
|
225
|
+
### Clientes
|
|
226
|
+
|
|
227
|
+
</div>
|
|
228
|
+
|
|
229
|
+
```ruby
|
|
230
|
+
AbacatePay.customers.list
|
|
231
|
+
AbacatePay.customers.get('cust_123')
|
|
232
|
+
AbacatePay.customers.delete('cust_123')
|
|
233
|
+
|
|
234
|
+
AbacatePay.customers.create(
|
|
235
|
+
AbacatePay::Resources::Customers.new(
|
|
236
|
+
metadata: AbacatePay::Resources::Customers::Metadata.new(
|
|
119
237
|
name: 'Abacate Lover',
|
|
120
238
|
cellphone: '01912341234',
|
|
121
239
|
email: 'lover@abacate.com',
|
|
@@ -125,42 +243,245 @@ customer_client.create(
|
|
|
125
243
|
)
|
|
126
244
|
```
|
|
127
245
|
|
|
128
|
-
|
|
246
|
+
<div align="center">
|
|
247
|
+
|
|
248
|
+
### Produtos
|
|
249
|
+
|
|
250
|
+
</div>
|
|
251
|
+
|
|
252
|
+
```ruby
|
|
253
|
+
AbacatePay.products.create(
|
|
254
|
+
AbacatePay::Resources::Products.new(
|
|
255
|
+
external_id: 'my-product-1',
|
|
256
|
+
name: 'Monthly Plan',
|
|
257
|
+
price: 2990, # R$ 29,90 em centavos
|
|
258
|
+
currency: 'BRL',
|
|
259
|
+
description: 'Acesso a todos os recursos',
|
|
260
|
+
cycle: 'MONTHLY' # ou nil para pagamento único
|
|
261
|
+
)
|
|
262
|
+
)
|
|
263
|
+
```
|
|
129
264
|
|
|
130
|
-
|
|
131
|
-
https://abacatepay.readme.io/reference
|
|
265
|
+
<div align="center">
|
|
132
266
|
|
|
133
|
-
|
|
267
|
+
### Cupons
|
|
134
268
|
|
|
135
|
-
|
|
269
|
+
</div>
|
|
136
270
|
|
|
137
|
-
|
|
138
|
-
|
|
271
|
+
```ruby
|
|
272
|
+
AbacatePay.coupons.create(
|
|
273
|
+
AbacatePay::Resources::Coupons.new(
|
|
274
|
+
code: 'SAVE20',
|
|
275
|
+
discount: 20,
|
|
276
|
+
discount_kind: 'PERCENTAGE', # ou 'FIXED'
|
|
277
|
+
max_redeems: 100
|
|
278
|
+
)
|
|
279
|
+
)
|
|
139
280
|
|
|
140
|
-
|
|
141
|
-
git checkout -b feature/your-feature-name
|
|
281
|
+
AbacatePay.coupons.toggle('coup_123')
|
|
142
282
|
```
|
|
143
283
|
|
|
144
|
-
|
|
284
|
+
<div align="center">
|
|
145
285
|
|
|
146
|
-
|
|
147
|
-
|
|
286
|
+
### Assinaturas
|
|
287
|
+
|
|
288
|
+
Exigem exatamente um produto com `cycle` definido.
|
|
289
|
+
|
|
290
|
+
</div>
|
|
291
|
+
|
|
292
|
+
```ruby
|
|
293
|
+
AbacatePay.subscriptions.create(
|
|
294
|
+
AbacatePay::Resources::Subscriptions.new(
|
|
295
|
+
methods: ['PIX'],
|
|
296
|
+
customer: AbacatePay::Resources::Customers.new(id: 'cust_123'),
|
|
297
|
+
products: [
|
|
298
|
+
AbacatePay::Resources::Billings::Product.new(
|
|
299
|
+
external_id: 'plan-monthly',
|
|
300
|
+
name: 'Monthly Plan',
|
|
301
|
+
price: 2990,
|
|
302
|
+
quantity: 1
|
|
303
|
+
)
|
|
304
|
+
]
|
|
305
|
+
)
|
|
306
|
+
)
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
<div align="center">
|
|
310
|
+
|
|
311
|
+
### PIX transparente (QR Code)
|
|
312
|
+
|
|
313
|
+
</div>
|
|
314
|
+
|
|
315
|
+
```ruby
|
|
316
|
+
AbacatePay.transparents.create(
|
|
317
|
+
AbacatePay::Resources::Transparents.new(
|
|
318
|
+
amount: 1000,
|
|
319
|
+
description: 'Pedido #123',
|
|
320
|
+
expires_in: 3600
|
|
321
|
+
)
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
AbacatePay.transparents.check('tr_123')
|
|
325
|
+
AbacatePay.transparents.simulate_payment('tr_123') # apenas em dev mode
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
<div align="center">
|
|
329
|
+
|
|
330
|
+
### Transferências PIX
|
|
331
|
+
|
|
332
|
+
</div>
|
|
333
|
+
|
|
334
|
+
```ruby
|
|
335
|
+
AbacatePay.pix.send_pix(
|
|
336
|
+
AbacatePay::Resources::PixTransfers.new(
|
|
337
|
+
amount: 500,
|
|
338
|
+
external_id: 'transfer-001',
|
|
339
|
+
description: 'Pagamento ao fornecedor',
|
|
340
|
+
key: '12345678900',
|
|
341
|
+
key_type: 'CPF' # CPF, CNPJ, PHONE, EMAIL, RANDOM, BR_CODE
|
|
342
|
+
)
|
|
343
|
+
)
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
<div align="center">
|
|
347
|
+
|
|
348
|
+
### Saques
|
|
349
|
+
|
|
350
|
+
Valor mínimo de R$ 3,50.
|
|
351
|
+
|
|
352
|
+
</div>
|
|
353
|
+
|
|
354
|
+
```ruby
|
|
355
|
+
AbacatePay.payouts.create(
|
|
356
|
+
AbacatePay::Resources::Payouts.new(
|
|
357
|
+
amount: 5000,
|
|
358
|
+
external_id: 'withdrawal-001',
|
|
359
|
+
description: 'Saque mensal'
|
|
360
|
+
)
|
|
361
|
+
)
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
<div align="center">
|
|
365
|
+
|
|
366
|
+
### Links de pagamento
|
|
367
|
+
|
|
368
|
+
Um link reutilizável, pago por vários clientes de forma independente — vendas em massa, rifas, formulários de inscrição. Para uma cobrança por cliente, use `checkouts`.
|
|
369
|
+
|
|
370
|
+
</div>
|
|
371
|
+
|
|
372
|
+
```ruby
|
|
373
|
+
link = AbacatePay.payment_links.create(
|
|
374
|
+
AbacatePay::Resources::Checkouts.new(
|
|
375
|
+
methods: ['PIX', 'CARD'],
|
|
376
|
+
external_id: 'campanha-black-friday',
|
|
377
|
+
products: [
|
|
378
|
+
AbacatePay::Resources::Billings::Product.new(external_id: 'prod_123', quantity: 1)
|
|
379
|
+
]
|
|
380
|
+
)
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
puts link.url # compartilhe esta URL
|
|
148
384
|
```
|
|
149
385
|
|
|
150
|
-
|
|
386
|
+
<div align="center">
|
|
387
|
+
|
|
388
|
+
### Estornos
|
|
389
|
+
|
|
390
|
+
O estorno é sempre integral — a AbacatePay não faz estorno parcial.
|
|
391
|
+
|
|
392
|
+
</div>
|
|
393
|
+
|
|
394
|
+
```ruby
|
|
395
|
+
AbacatePay.checkouts.refund('bill_abc123xyz')
|
|
396
|
+
AbacatePay.transparents.refund('pix_char_abc123xyz')
|
|
397
|
+
AbacatePay.payment_links.refund('char_abc123xyz')
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
<div align="center">
|
|
401
|
+
|
|
402
|
+
### Cancelar assinatura
|
|
403
|
+
|
|
404
|
+
Cancela imediatamente; parcelas futuras pendentes são canceladas junto.
|
|
405
|
+
|
|
406
|
+
</div>
|
|
407
|
+
|
|
408
|
+
```ruby
|
|
409
|
+
AbacatePay.subscriptions.cancel('subs_abc123xyz')
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
<div align="center">
|
|
413
|
+
|
|
414
|
+
### Registro de webhooks
|
|
415
|
+
|
|
416
|
+
Isto gerencia **para onde** a AbacatePay entrega os eventos. Para verificar uma entrega recebida, use `Webhooks.construct_event`.
|
|
417
|
+
|
|
418
|
+
</div>
|
|
419
|
+
|
|
420
|
+
```ruby
|
|
421
|
+
AbacatePay.webhook_endpoints.create(
|
|
422
|
+
name: 'Pagamentos',
|
|
423
|
+
endpoint: 'https://meusite.com/webhooks/abacatepay', # precisa ser HTTPS
|
|
424
|
+
secret: ENV['ABACATEPAY_WEBHOOK_SECRET'],
|
|
425
|
+
events: ['checkout.completed', 'subscription.renewed']
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
AbacatePay.webhook_endpoints.list
|
|
429
|
+
AbacatePay.webhook_endpoints.delete('wh_123')
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
<div align="center">
|
|
433
|
+
|
|
434
|
+
### Loja
|
|
435
|
+
|
|
436
|
+
</div>
|
|
437
|
+
|
|
438
|
+
```ruby
|
|
439
|
+
store = AbacatePay.store.get
|
|
440
|
+
store.balance.available # => 10000
|
|
441
|
+
store.balance.pending # => 500
|
|
442
|
+
store.balance.blocked # => 0
|
|
443
|
+
|
|
444
|
+
AbacatePay.store.revenue(start_date: '2026-01-01', end_date: '2026-03-30')
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
<div align="center">
|
|
448
|
+
|
|
449
|
+
## Enums
|
|
450
|
+
|
|
451
|
+
Os valores são validados na construção do recurso — um valor inválido levanta `ArgumentError` antes de qualquer chamada de rede.
|
|
452
|
+
|
|
453
|
+
| Enum | Valores |
|
|
454
|
+
|---|---|
|
|
455
|
+
| `Billings::Methods` | `PIX`, `CARD` |
|
|
456
|
+
| `Billings::Frequencies` | `ONE_TIME`, `WEEKLY`, `MONTHLY`, `SEMIANNUALLY`, `ANNUALLY`, `MULTIPLE_PAYMENTS` |
|
|
457
|
+
| `Billings::Statuses` | `PENDING`, `EXPIRED`, `CANCELLED`, `PAID`, `REFUNDED` |
|
|
458
|
+
| `Products::Cycles` | `WEEKLY`, `MONTHLY`, `SEMIANNUALLY`, `ANNUALLY` |
|
|
459
|
+
| `Coupons::Statuses` | `ACTIVE`, `INACTIVE`, `EXPIRED` |
|
|
460
|
+
| `Coupons::DiscountKinds` | `PERCENTAGE`, `FIXED` |
|
|
461
|
+
| `Pix::KeyTypes` | `CPF`, `CNPJ`, `PHONE`, `EMAIL`, `RANDOM`, `BR_CODE` |
|
|
462
|
+
| `Transfers::Statuses` | `PENDING`, `COMPLETE`, `CANCELLED`, `EXPIRED`, `REFUNDED`, `FAILED` |
|
|
463
|
+
| `Payouts::Statuses` | `PENDING`, `COMPLETE`, `CANCELLED`, `EXPIRED`, `REFUNDED` |
|
|
464
|
+
|
|
465
|
+
## Contribuindo
|
|
466
|
+
|
|
467
|
+
</div>
|
|
151
468
|
|
|
152
469
|
```bash
|
|
153
|
-
git
|
|
470
|
+
git clone https://github.com/AbacatePay/abacatepay-ruby-sdk.git
|
|
471
|
+
cd abacatepay-ruby-sdk
|
|
472
|
+
bundle install
|
|
473
|
+
bundle exec rake # specs + rubocop
|
|
154
474
|
```
|
|
155
475
|
|
|
156
|
-
|
|
476
|
+
<div align="center">
|
|
477
|
+
|
|
478
|
+
Antes de abrir um PR, garanta que `bundle exec rake` passa e que a cobertura não caiu — o CI roda os specs em Ruby 3.2, 3.3, 3.4 e 4.0, mais RuboCop, auditoria de dependências e build do gem.
|
|
479
|
+
|
|
480
|
+
## Licença
|
|
157
481
|
|
|
158
|
-
|
|
482
|
+
MIT
|
|
159
483
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
- Includes appropriate tests
|
|
163
|
-
- Passes all existing tests (bundle exec rspec)
|
|
164
|
-
- Passes code style checks (bundle exec rubocop)
|
|
484
|
+
Feito com 🥑 pela equipe AbacatePay</br>
|
|
485
|
+
Open source, de verdade.
|
|
165
486
|
|
|
166
|
-
|
|
487
|
+
</div>
|
data/Rakefile
CHANGED
data/abacatepay-ruby.gemspec
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "lib/
|
|
3
|
+
require_relative "lib/abacate_pay/version"
|
|
4
4
|
|
|
5
5
|
Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = "abacatepay-ruby"
|
|
@@ -8,17 +8,21 @@ Gem::Specification.new do |spec|
|
|
|
8
8
|
spec.authors = ["Matheus Cardoso"]
|
|
9
9
|
spec.email = ["mathuscardoso@gmail.com"]
|
|
10
10
|
|
|
11
|
-
spec.summary = "AbacatePay Ruby
|
|
12
|
-
spec.description = "The easiest way to integrate your Ruby
|
|
11
|
+
spec.summary = "AbacatePay Ruby SDK for you to start receiving payments in seconds"
|
|
12
|
+
spec.description = "The easiest way to integrate your Ruby application with AbacatePay Gateway " \
|
|
13
|
+
"for payments, subscriptions, PIX transfers, and more."
|
|
13
14
|
spec.homepage = "https://www.abacatepay.com/"
|
|
14
15
|
spec.license = "MIT"
|
|
15
|
-
|
|
16
|
+
# faraday 2.x requires Ruby >= 3.0 and the pinned Bundler requires >= 3.2.
|
|
17
|
+
# 3.2 is the oldest version exercised by CI; 2.6 was never actually installable.
|
|
18
|
+
spec.required_ruby_version = ">= 3.2.0"
|
|
16
19
|
|
|
17
|
-
# spec.metadata["allowed_push_host"] = "https://github.com/AbacatePay
|
|
20
|
+
# spec.metadata["allowed_push_host"] = "https://rubygems.pkg.github.com/AbacatePay"
|
|
18
21
|
|
|
19
22
|
spec.metadata["homepage_uri"] = spec.homepage
|
|
20
23
|
spec.metadata["source_code_uri"] = "https://github.com/AbacatePay/abacatepay-ruby-sdk"
|
|
21
24
|
spec.metadata["changelog_uri"] = "https://github.com/AbacatePay/abacatepay-ruby-sdk/blob/main/CHANGELOG.md"
|
|
25
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
|
22
26
|
|
|
23
27
|
# Specify which files should be added to the gem when it is released.
|
|
24
28
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
@@ -33,14 +37,16 @@ Gem::Specification.new do |spec|
|
|
|
33
37
|
spec.require_paths = ["lib"]
|
|
34
38
|
|
|
35
39
|
# Runtime dependencies
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
# >= 2.14.3 excludes CVE-2026-54297 (stack-exhaustion DoS in
|
|
41
|
+
# NestedParamsEncoder). The lockfile only protects this repo — consumers are
|
|
42
|
+
# protected by the constraint here.
|
|
43
|
+
spec.add_dependency "faraday", "~> 2.14", ">= 2.14.3"
|
|
38
44
|
|
|
39
45
|
# Development dependencies
|
|
40
|
-
spec.add_development_dependency "
|
|
46
|
+
spec.add_development_dependency "bundler-audit", "~> 0.9"
|
|
47
|
+
spec.add_development_dependency "rspec", "~> 3.12"
|
|
41
48
|
spec.add_development_dependency "rubocop", "~> 1.57"
|
|
42
|
-
spec.add_development_dependency "rubocop-
|
|
43
|
-
spec.add_development_dependency "rubocop-rspec", "~> 2.25"
|
|
49
|
+
spec.add_development_dependency "rubocop-rspec", "~> 3.0"
|
|
44
50
|
spec.add_development_dependency "simplecov", "~> 0.22"
|
|
45
51
|
|
|
46
52
|
# For more information and examples about making a new gem, check out our
|