rail0-sdk 1.8.1 → 1.10.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.
data/lib/rail0/types.rb CHANGED
@@ -43,10 +43,24 @@ module Rail0
43
43
  # A single balance line — the native gas token or one ERC-20.
44
44
  AssetBalance = Struct.new(
45
45
  :symbol, # String
46
- :address, # Token contract address; null for the native balance.
46
+ :address, # String | nil — Token contract address; null for the native balance.
47
47
  :decimals, # Integer
48
48
  :raw, # String — Balance in base units (exact).
49
49
  :amount, # String — Human-decimal balance.
50
+ :payout, # What a payout in this token keeps back for gas — on every ERC-20 line; null on the native balance.
51
+ keyword_init: true
52
+ )
53
+
54
+ # The gas figures of a payout in this token on this chain: whether the chain's gas IS this very
55
+ # token (`native_gas`; Arc's USDC) and, then, the allowance POST /payouts/prepare keeps back from
56
+ # `all`, from a typed amount's ceiling and from the proof (`gas_allowance` = gas_limit ×
57
+ # max_fee_per_gas in base units, the charge the EVM takes before a transfer runs; `0` on any other
58
+ # chain). Null allowance when the fee could not be read. The reserves a payout keeps back are
59
+ # decided at payout time: GET /payout_destinations/{id}/reserves.
60
+ BalancePayout = Struct.new(
61
+ :native_gas, # Boolean
62
+ :gas_allowance, # String | nil
63
+ :gas_allowance_formatted, # String | nil
50
64
  keyword_init: true
51
65
  )
52
66
 
@@ -57,6 +71,15 @@ module Rail0
57
71
  keyword_init: true
58
72
  )
59
73
 
74
+ # What an account still has in motion (GET /admin/accounts/{id}/exposure, and `exposure` on a 409
75
+ # account_has_open_exposure).
76
+ AccountExposure = Struct.new(
77
+ :payments, # Hash
78
+ :payouts, # Hash
79
+ :empty, # Boolean — true when every count is zero.
80
+ keyword_init: true
81
+ )
82
+
60
83
  # The error envelope: exactly code (stable, the only field to branch on), title (short label) and
61
84
  # detail (a sentence a UI can print verbatim). The legacy status/message/error aliases were removed
62
85
  # in #252.
@@ -170,9 +193,11 @@ module Rail0
170
193
  Blockchain = Struct.new(
171
194
  :chain_id, # Integer
172
195
  :name, # String
196
+ :slug, # String — The chain's short name, the same for its testnet and its mainnet (`arc` is Arc Testnet on a testnet gateway, Arc on production): a gateway serves one network class, so a client may name the chain by slug instead of chain_id. Lowercase, unique per network class.
173
197
  :native_symbol, # String
174
198
  :network_type, # String
175
199
  :explorer_url, # String
200
+ :public_rpc_urls, # Array — Public, keyless RPC endpoints published for clients that read the chain directly (a balance, a receipt), in failover order: try them in turn. Not necessarily the endpoints the gateway itself uses.
176
201
  :required_confirmations, # Integer — Confirmations this gateway waits for before treating a transaction as settled. The FALLBACK rule: where the chain serves a finality tag (see finality_tag) that tag governs instead, so a client showing this number on such a chain is describing a rule that is not in force.
177
202
  :finality_tag, # String — The block tag the chain calls settled (`safe`, `finalized`), when it serves one — and what the gateway actually gates on. Null where the chain serves none, in which case required_confirmations is counted.
178
203
  :contract, # ChainContract
@@ -211,9 +236,9 @@ module Rail0
211
236
  Wallet = Struct.new(
212
237
  :id, # String
213
238
  :address, # String
214
- :label,
239
+ :label, # String | nil
215
240
  :active, # Boolean
216
- :deactivated_by, # Who switched the wallet off: `owner` (a session signed in with this wallet) or `operator` (an admin session). Null while active, and on a switch-off that predates the record — treated as `operator`. A wallet an operator switched off can be switched back on only by an operator (403 `wallet_deactivated_by_operator`). Always null on GET /payment_methods, which serves active wallets only.
241
+ :deactivated_by, # String | nil — Who switched the wallet off: `owner` (a session signed in with this wallet) or `operator` (an admin session). Null while active, and on a switch-off that predates the record — treated as `operator`. A wallet an operator switched off can be switched back on only by an operator (403 `wallet_deactivated_by_operator`). Always null on GET /payment_methods, which serves active wallets only.
217
242
  keyword_init: true
218
243
  )
219
244
 
@@ -232,9 +257,9 @@ module Rail0
232
257
  WalletWithTokens = Struct.new(
233
258
  :id, # String
234
259
  :address, # String
235
- :label,
260
+ :label, # String | nil
236
261
  :active, # Boolean
237
- :deactivated_by, # Who switched the wallet off: `owner` (a session signed in with this wallet) or `operator` (an admin session). Null while active, and on a switch-off that predates the record — treated as `operator`. A wallet an operator switched off can be switched back on only by an operator (403 `wallet_deactivated_by_operator`). Always null on GET /payment_methods, which serves active wallets only.
262
+ :deactivated_by, # String | nil — Who switched the wallet off: `owner` (a session signed in with this wallet) or `operator` (an admin session). Null while active, and on a switch-off that predates the record — treated as `operator`. A wallet an operator switched off can be switched back on only by an operator (403 `wallet_deactivated_by_operator`). Always null on GET /payment_methods, which serves active wallets only.
238
263
  :tokens, # Array
239
264
  keyword_init: true
240
265
  )
@@ -255,21 +280,21 @@ module Rail0
255
280
  :payer, # String
256
281
  :payee, # String
257
282
  :token, # String
258
- :decimals, # Decimals of the payment's token: divide `amount`, `capturable_amount` and `refundable_amount` (base units) by 10^decimals to render them, with no GET /tokens join on `token` + `chain_id`. Resolved from the gateway's in-memory chain catalogue, retired tokens and archived contract versions included. Null only when the gateway cannot resolve the token (a contract it has not loaded, a token deleted outright) — fall back to GET /tokens then.
283
+ :decimals, # Integer | nil — Decimals of the payment's token: divide `amount`, `capturable_amount` and `refundable_amount` (base units) by 10^decimals to render them, with no GET /tokens join on `token` + `chain_id`. Resolved from the gateway's in-memory chain catalogue, retired tokens and archived contract versions included. Null only when the gateway cannot resolve the token (a contract it has not loaded, a token deleted outright) — fall back to GET /tokens then.
259
284
  :authorization_expiry, # Integer
260
285
  :refund_expiry, # Integer
261
286
  :escrow_stranded, # Boolean — True exactly inside the stranded-escrow window (#233): a partial capture has permanently ruled void out, and release only opens at authorization_expiry — so no verb can return the buyer's uncaptured escrow until then. Mirrors RAIL0.sol; the gateway names the window, it cannot shorten it.
262
287
  :escrow_returnable_at, # String — When the stranded escrow becomes returnable (release opens) — the authorization expiry as ISO-8601. Null whenever nothing is stranded, so presence alone is the signal.
263
288
  :disputed, # Boolean — True while an open dispute exists.
264
289
  :in_flight, # Boolean — True while one of the payment's transactions is on its way to the chain and not yet settled: status `submitting`, `submitted`, or `pending` holding its signed transaction (the `redrivable` rows — signed and handed over, broadcast not yet sent). A `pending` row still awaiting its signature (an unfinished prepare) does not count, nor do `confirmed`/`failed`. While true the mirrored balances are about to move, so a client should disable further actions on the payment. Carried by list rows too, which embed no transactions; computed for a whole page in one query.
265
- :last_error_code, # Decoded reason of the last failed on-chain attempt; null once the payment makes forward progress. Non-null means the latest attempt failed.
266
- :last_error_message, # Human-readable form of last_error_code.
267
- :description,
268
- :reference, # This payment's identifier in the merchant's own system; set at create, correctable by the payee.
269
- :reference_origin, # The system the reference comes from, a lowercase slug (e.g. commercelayer).
270
- :merchant_note, # The payee's internal note (PATCH /payments/{id}). Present only when the session is the payment's PAYEE, and on the operator's Full view; absent for the payer.
271
- :metadata,
272
- :signed_at, # When the payer signature was stored (null while unsigned).
290
+ :last_error_code, # String | nil — Decoded reason of the last failed on-chain attempt; null once the payment makes forward progress. Non-null means the latest attempt failed.
291
+ :last_error_message, # String | nil — Human-readable form of last_error_code.
292
+ :description, # String | nil
293
+ :reference, # String | nil — This payment's identifier in the merchant's own system; set at create, correctable by the payee.
294
+ :reference_origin, # String | nil — The system the reference comes from, a lowercase slug (e.g. commercelayer).
295
+ :merchant_note, # String | nil — The payee's internal note (PATCH /payments/{id}). Present only when the session is the payment's PAYEE, and on the operator's Full view; absent for the payer.
296
+ :metadata, # Hash | nil
297
+ :signed_at, # String | nil — When the payer signature was stored (null while unsigned).
273
298
  :created_at, # String
274
299
  :updated_at, # String
275
300
  keyword_init: true
@@ -283,23 +308,23 @@ module Rail0
283
308
  :reason, # String — On-chain bytes32 reason the dispute was opened with (hex); the all-zero word when no reason was given; kept verbatim even when it is outside the dispute-reason dictionary.
284
309
  :reason_code, # DisputeOpenReason | nil — The DisputeOpenReason code `reason` reads as; null when no reason was given (the zero bytes32) or when the bytes32 is not in the dictionary (a direct contract call).
285
310
  :reason_description, # String — English description of `reason_code`; "No reason given" when `reason` is the zero bytes32; "Unrecognised reason" when it is a non-zero bytes32 outside the dictionary.
286
- :opened_block,
311
+ :opened_block, # Integer | nil
287
312
  :opened_at, # String
288
- :closed_by,
289
- :close_reason, # On-chain bytes32 close reason (hex); the all-zero word when closed with no reason; null while the dispute is open.
313
+ :closed_by, # String | nil
314
+ :close_reason, # String | nil — On-chain bytes32 close reason (hex); the all-zero word when closed with no reason; null while the dispute is open.
290
315
  :close_reason_code, # DisputeCloseReason | DisputeSystemCloseReason | nil — The code `close_reason` reads as: a DisputeCloseReason, or the system DisputeSystemCloseReason `full_refund` when a full refund auto-closed the dispute. Null while open, when closed with no reason (the zero bytes32), or when the bytes32 is not in the dictionary.
291
- :close_reason_description, # English description of `close_reason_code`; "No reason given" when `close_reason` is the zero bytes32; "Unrecognised reason" when it is a non-zero bytes32 outside the dictionary; null while open.
292
- :closed_block,
293
- :closed_at,
316
+ :close_reason_description, # String | nil — English description of `close_reason_code`; "No reason given" when `close_reason` is the zero bytes32; "Unrecognised reason" when it is a non-zero bytes32 outside the dictionary; null while open.
317
+ :closed_block, # Integer | nil
318
+ :closed_at, # String | nil
294
319
  keyword_init: true
295
320
  )
296
321
 
297
322
  # What the callback did with a test event (POST /webhooks/{id}/test).
298
323
  WebhookTestResult = Struct.new(
299
324
  :delivered, # Boolean — The endpoint answered 2xx.
300
- :response_code, # The HTTP status it answered; null when no response came (see error_reason).
301
- :response_message, # Up to 1000 printable characters of its response body.
302
- :error_reason, # Why no response came: a refused address, a TLS or connection error, the deadline.
325
+ :response_code, # String | nil — The HTTP status it answered; null when no response came (see error_reason).
326
+ :response_message, # String | nil — Up to 1000 printable characters of its response body.
327
+ :error_reason, # String | nil — Why no response came: a refused address, a TLS or connection error, the deadline.
303
328
  :duration_ms, # Integer — How long the attempt took.
304
329
  keyword_init: true
305
330
  )
@@ -310,22 +335,22 @@ module Rail0
310
335
  :operation, # String — Which on-chain call this row attempts. A SUPERSET of the `{operation}` path enum: `dispute` and `close_dispute` have their own hand-written routes rather than living under the generic namespace, but they mint transaction rows like any other operation, so a generated client must be able to represent them.
311
336
  :status, # String
312
337
  :redrivable, # Boolean — True when this transaction's broadcast can be re-enqueued: it is `pending` and the gateway holds its signed transaction, i.e. a send that was prepared and signed but never reached the chain. The same predicate `POST /payments/{id}/transactions/{transaction_id}/redrive` guards on, so a client can offer the action exactly when it will succeed instead of on a 422. False on a `pending` row that holds no signed transaction - there the next step is submitting the signature, not a redrive.
313
- :error_code, # Decoded failure code, null unless `status` is "failed". Same catalogue as an error body's `code`: a RAIL0 custom error (`not_payee`), a token-level revert (`insufficient_token_balance`, `invalid_token_signature`, `authorization_already_used`), a Solidity panic, or a rejection that stopped the broadcast before the chain saw it (`insufficient_gas_funds`, `nonce_too_low`).
338
+ :error_code, # String | nil — Decoded failure code, null unless `status` is "failed". Same catalogue as an error body's `code`: a RAIL0 custom error (`not_payee`), a token-level revert (`insufficient_token_balance`, `invalid_token_signature`, `authorization_already_used`), a Solidity panic, or a rejection that stopped the broadcast before the chain saw it (`insufficient_gas_funds`, `nonce_too_low`).
314
339
  :error_title, # String — Short label for `error_code`; null unless failed.
315
340
  :error_detail, # String — Sentence explaining the failure; null unless failed. Carries the chain's own words when the revert was not one the gateway recognises.
316
- :unsigned_transaction,
317
- :transaction_hash,
318
- :sender, # The address that SIGNED the submitted transaction, recovered from the signature by the gateway at submit — a fact, not a client claim. Null where the gateway held no signature to recover from (a report-by-hash submit, where the wallet broadcast it itself) or where nothing has been submitted yet. This is what makes `release` gas attributable: that operation is payer-OR-payee, so whose cost it is depends on who signed.
319
- :amount, # Amount in token BASE units. On capture and refund it is the amount the caller asked for. On void and release it is PROVISIONAL — those operations carry no amount and move the whole uncaptured escrow, so this is the capturable residual as of prepare, re-sealed with the exact on-chain amount when the indexer confirms.
320
- :block_number,
321
- :gas_used, # Gas units used, mirrored from the indexer on confirm.
322
- :gas_limit, # Gas limit, mirrored from the indexer on confirm.
323
- :effective_gas_price, # Effective gas price in wei, mirrored from the indexer on confirm.
324
- :base_fee_per_gas, # Block base fee per gas in wei, mirrored from the indexer on confirm.
325
- :gas_cost, # Total gas cost in wei (gas_used * effective_gas_price); derived, null until confirmed.
326
- :pending_at,
327
- :submitted_at,
328
- :confirmed_at,
341
+ :unsigned_transaction, # String | nil
342
+ :transaction_hash, # String | nil
343
+ :sender, # String | nil — The address that SIGNED the submitted transaction, recovered from the signature by the gateway at submit — a fact, not a client claim. Null where the gateway held no signature to recover from (a report-by-hash submit, where the wallet broadcast it itself) or where nothing has been submitted yet. This is what makes `release` gas attributable: that operation is payer-OR-payee, so whose cost it is depends on who signed.
344
+ :amount, # String | nil — Amount in token BASE units. On capture and refund it is the amount the caller asked for. On void and release it is PROVISIONAL — those operations carry no amount and move the whole uncaptured escrow, so this is the capturable residual as of prepare, re-sealed with the exact on-chain amount when the indexer confirms.
345
+ :block_number, # Integer | nil
346
+ :gas_used, # String | nil — Gas units used, mirrored from the indexer on confirm.
347
+ :gas_limit, # String | nil — Gas limit, mirrored from the indexer on confirm.
348
+ :effective_gas_price, # String | nil — Effective gas price in wei, mirrored from the indexer on confirm.
349
+ :base_fee_per_gas, # String | nil — Block base fee per gas in wei, mirrored from the indexer on confirm.
350
+ :gas_cost, # String | nil — Total gas cost in wei (gas_used * effective_gas_price); derived, null until confirmed.
351
+ :pending_at, # String | nil
352
+ :submitted_at, # String | nil
353
+ :confirmed_at, # String | nil
329
354
  :created_at, # String
330
355
  :updated_at, # String
331
356
  keyword_init: true
@@ -339,10 +364,10 @@ module Rail0
339
364
  :address, # String
340
365
  :version, # String — Semver, and every ACTIVE deployment must agree on the one the code targets.
341
366
  :deployed_at, # String
342
- :start_block, # Where the indexer starts. Null means the deployment block.
367
+ :start_block, # Integer | nil — Where the indexer starts. Null means the deployment block.
343
368
  :active, # Boolean — The single deployment new payments are opened against, at most one per chain.
344
369
  :archived, # Boolean — Always false here: the listing excludes archived deployments.
345
- :archived_at,
370
+ :archived_at, # String | nil
346
371
  :created_at, # String
347
372
  :updated_at, # String
348
373
  keyword_init: true
@@ -356,7 +381,7 @@ module Rail0
356
381
  Account = Struct.new(
357
382
  :id, # String
358
383
  :name, # String
359
- :email,
384
+ :email, # String | nil
360
385
  :priority_tip, # Boolean — Whether the merchant's own transactions tip the network's suggested priority fee (true, the default) or the chain's minimum tip (false: 0 on most chains, 25 gwei on Polygon PoS/Amoy). The buyer's dispute/close_dispute never read it.
361
386
  :authorization_ttl, # Integer — Seconds an authorization of the account's new payments stays capturable after the payment is created: the account's own value, or the gateway default (AUTHORIZATION_TTL).
362
387
  :refund_ttl, # Integer — Seconds the account's new payments stay refundable, and open to a dispute, after they are created: the account's own value, or the gateway default (REFUND_TTL).
@@ -402,15 +427,15 @@ module Rail0
402
427
  :name, # String
403
428
  :email, # String — Lowercase.
404
429
  :address, # String — Lowercase 0x + 40 hex.
405
- :created_by, # The operator account of an invite; null for a sign-up.
430
+ :created_by, # String | nil — The operator account of an invite; null for a sign-up.
406
431
  :link_version, # Integer — The version of the last link minted; a link for any lower one answers onboarding_link_superseded.
407
432
  :last_sent_at, # String — When the last send was queued.
408
433
  :send_count, # Integer — Sends queued in all (0 for a request migrated from a pending account, which has no link in the current format yet).
409
- :last_delivered_at, # When the provider accepted the last send.
410
- :last_send_error, # A short fixed code for why the last send failed (provider_rejected, timeout, email_domain_not_allowed, …); null when it was delivered or is in flight.
434
+ :last_delivered_at, # String | nil — When the provider accepted the last send.
435
+ :last_send_error, # String | nil — A short fixed code for why the last send failed (provider_rejected, timeout, email_domain_not_allowed, …); null when it was delivered or is in flight.
411
436
  :expires_at, # String — When the last link, and the open request, expire.
412
- :completed_at, # When the claim created the account.
413
- :terms_version, # The terms version accepted at the claim.
437
+ :completed_at, # String | nil — When the claim created the account.
438
+ :terms_version, # String | nil — The terms version accepted at the claim.
414
439
  :created_at, # String
415
440
  :updated_at, # String
416
441
  :status, # String
@@ -541,17 +566,19 @@ module Rail0
541
566
  )
542
567
 
543
568
  EventCallback = Struct.new(
544
- :id, # String
545
- :webhook_id, # String
546
- :payment_id, # String
547
- :topic, # String
548
- :callback_url, # String
549
- :response_code,
550
- :response_message,
551
- :error_reason,
552
- :status, # String
553
- :created_at, # String
554
- :payload, # The JSON request body POSTed to the callback URL (decompressed).
569
+ :id, # String
570
+ :webhook_id, # String
571
+ :payment_id, # String | nil — The payment a payments.* delivery is about. Exactly one of payment_id, payout_id and payout_destination_id is set.
572
+ :payout_id, # String | nil — The payout a payouts.* delivery is about.
573
+ :payout_destination_id, # String | nil — The destination a payout_destinations.verified delivery is about.
574
+ :topic, # String
575
+ :callback_url, # String
576
+ :response_code, # String | nil
577
+ :response_message, # String | nil
578
+ :error_reason, # String | nil
579
+ :status, # String
580
+ :created_at, # String
581
+ :payload, # String | nil — The JSON request body POSTed to the callback URL (decompressed).
555
582
  keyword_init: true
556
583
  )
557
584
 
@@ -564,5 +591,107 @@ module Rail0
564
591
  :contract_address, # String — Address (lowercase) of the RAIL0 deployment the payment is bound to, archived versions included. The sweeper accepts a receipt's event only when this contract emitted it.
565
592
  keyword_init: true
566
593
  )
594
+
595
+ # One entry of the payout audit trail, written in the same transaction as the change it records.
596
+ # Append-only.
597
+ PayoutEvent = Struct.new(
598
+ :id, # String
599
+ :action, # String
600
+ :actor, # String — Who did it: the lowercase 0x address of the session wallet; `system` for the gateway's own settlement (Recovery); `operator:<administrator id>` reserved for an operator (none today).
601
+ :changes, # Hash | nil — `{"before": {…}, "after": {…}}` of the fields the event changed, either side optional. Amounts in base units. Never a signature or a payload. `destination.created` and `destination.min_amount_changed` also carry `confirmed_details`: `{"version": "details_v1", "by": <session address>, "at": <ISO 8601 UTC>}`, the merchant's attestation that they checked the details at the venue.
602
+ :destination_id, # String | nil — The destination, also on every payout event.
603
+ :payout_id, # String | nil — Null for a destination event, and once Retention purged the payout (a never-signed prepare).
604
+ :wallet_id, # String — The destination's / payout's wallet (not necessarily the actor's).
605
+ :created_at, # String
606
+ keyword_init: true
607
+ )
608
+
609
+ # An account named and nothing more, embedded where an operator listing must say whose row each is.
610
+ AccountSummary = Struct.new(
611
+ :id, # String
612
+ :name, # String
613
+ keyword_init: true
614
+ )
615
+
616
+ PayoutDestination = Struct.new(
617
+ :id, # String
618
+ :wallet_id, # String
619
+ :chain_id, # Integer
620
+ :token, # String — ERC-20 address on that chain, lowercased.
621
+ :token_symbol, # String | nil
622
+ :address, # String — The deposit address, lowercased.
623
+ :label, # String — The merchant's name for it: never blank, unique (case-insensitive) among the account's live destinations.
624
+ :status, # String
625
+ :has_code, # Boolean | nil — Whether the address held code on this chain when registered (eth_getCode, best effort). An EOA and an undeployed contract look the same.
626
+ :min_amount, # String | nil — The venue's deposit minimum, base units; null = no minimum. A payout below it is refused (`payout_below_minimum`); the proof transfer is raised to it.
627
+ :no_minimum, # Boolean — true when the merchant stated the venue has no minimum deposit (`min_amount` is then null). false with a null `min_amount`: never stated (a destination registered before it was asked).
628
+ :min_amount_formatted, # String | nil — `min_amount` in human decimals (the token's decimals); null when there is no minimum, or when the token left the catalog.
629
+ :proof_payout_id, # String | nil
630
+ :verified_at, # String | nil
631
+ :disabled_at, # String | nil
632
+ :deleted_at, # String | nil — When the merchant deleted it (DELETE /payout_destinations/{id}); null for a live destination.
633
+ :created_at, # String
634
+ :updated_at, # String
635
+ keyword_init: true
636
+ )
637
+
638
+ # What a payout to the destination would keep back right now (GET
639
+ # /payout_destinations/{id}/reserves). Every amount is base units as a string, with its
640
+ # human-decimals twin (`*_formatted`, the token's decimals).
641
+ PayoutReserves = Struct.new(
642
+ :destination_id, # String
643
+ :chain_id, # Integer
644
+ :token, # String — ERC-20 address on that chain, lowercased.
645
+ :token_symbol, # String
646
+ :decimals, # Integer
647
+ :balance, # String — The wallet's balance of the token, read now.
648
+ :balance_formatted, # String
649
+ :refund_reserve, # String — The refundable balance of the wallet's payments in this token still inside their refund window.
650
+ :refund_reserve_formatted, # String
651
+ :refundable_payments, # Integer — How many payments `refund_reserve` covers: the refunds the wallet may still owe.
652
+ :native_gas, # Boolean — Whether the chain's gas is paid in this very token (Arc's USDC). The gas figures are `0` when it is not.
653
+ :gas_reserve, # String — Gas for `gas_refunds` refunds and for `open_authorizations` + `base_captures` captures, at their gas limits and the fee ceiling a prepare would set now; `0` off a native-gas chain. Counted over every token of the chain: on Arc a EURC payment's capture or refund is paid in USDC gas too.
654
+ :gas_reserve_formatted, # String
655
+ :gas_refunds, # Integer — The wallet's payments on this chain, in any token, still inside their refund window with something left to refund: the refunds the gas reserve pays for.
656
+ :open_authorizations, # Integer — The wallet's payments on this chain, in any token, still capturable (a capture's gas is the merchant wallet's).
657
+ :base_captures, # Integer — Captures the gas reserve pays for on top of the open authorizations, so the wallet can capture the payments it takes next.
658
+ :gas_allowance, # String — The payout transfer's own fee (gas_limit × max_fee_per_gas), always kept back on a native-gas chain; `0` elsewhere.
659
+ :gas_allowance_formatted, # String
660
+ :available, # String — balance − refund_reserve − gas_reserve − gas_allowance, floored at 0: what `amount: all` moves with both reserves kept (the default).
661
+ :available_formatted, # String
662
+ keyword_init: true
663
+ )
664
+
665
+ Payout = Struct.new(
666
+ :id, # String
667
+ :destination_id, # String
668
+ :wallet_id, # String
669
+ :chain_id, # Integer
670
+ :token, # String
671
+ :token_symbol, # String | nil
672
+ :address, # String — The recipient.
673
+ :amount, # String — Base units.
674
+ :amount_formatted, # String — Human decimals.
675
+ :refund_reserve, # String | nil — Base units this payout kept back in the wallet for refunds, decided at prepare; `0` when the merchant opted out (`keep_refund_reserve: false`); null for a proof.
676
+ :gas_reserve, # String | nil — Base units this payout kept back for the gas the wallet still owes (native-gas chains only, `0` elsewhere or when opted out with `keep_gas_reserve: false`); null for a proof.
677
+ :purpose, # String
678
+ :status, # String — `pending` (prepared, awaiting the signature) → `submitted` (hash known; still `submitted` once mined, until its block is final) → `confirmed` | `failed`. Both outcomes are decided only once the receipt's block is at or below the chain's finality bound (its `finality_tag` block, or head − `required_confirmations` for `depth` or a node that serves no tag) and still canonical; `payouts.confirmed` / `payouts.failed` fire then.
679
+ :unsigned_transaction, # String | nil — JSON of the EIP-1559 transaction to sign (`to` = the token, `data` = transfer(address,uint256)). Check it against the decoded fields beside it before signing.
680
+ :signed, # Boolean — Whether the gateway stores the wallet's signed transaction (the payload itself is never exposed). A `pending` payout with `signed: true` already has its `transaction_hash` and may be in a mempool: resend it (POST /payouts/{id}/resend); it cannot be re-prepared.
681
+ :transaction_hash, # String | nil — Keccak of the signed transaction, stored with it on submit (so a signed `pending` row has it too), or the hash the wallet reported.
682
+ :sender, # String | nil
683
+ :block_number, # Integer | nil — The receipt's block. Set when the gateway first sees the receipt (the payout stays `submitted` until that block is final) moved to the new block if a reorg re-includes the transaction elsewhere, and cleared only while no block holds it.
684
+ :mined_at, # String | nil — When the gateway first saw the receipt (its own clock, not the block's timestamp). Non-null on a `submitted` payout: mined, waiting for finality.
685
+ :gas_used, # String | nil
686
+ :error_code, # String | nil — When failed: `reverted` (mined, status 0), `foreign_transfer` (mined, but the receipt has no Transfer of this amount of this token from the wallet to this destination), `dropped` (not mined, and the wallet's confirmed nonce has passed the signed transaction's), `submission_timeout` (a reported hash no node has ever known, past SUBMITTED_TX_TTL), `cancelled` (unsigned, cancelled by the merchant with POST /payouts/{id}/cancel or by disabling its destination). `submission_timeout` and `dropped` are not final: POST /payouts/{id}/submitted with a late hash puts the payout back to `submitted`.
687
+ :error_title, # String | nil
688
+ :error_detail, # String | nil
689
+ :submitted_at, # String | nil
690
+ :confirmed_at, # String | nil
691
+ :failed_at, # String | nil
692
+ :created_at, # String
693
+ :updated_at, # String
694
+ keyword_init: true
695
+ )
567
696
  end
568
697
  end
data/lib/rail0/version.rb CHANGED
@@ -5,5 +5,5 @@ module Rail0
5
5
  # consumed by path from a sibling checkout, where the number bought nothing: no registry
6
6
  # ever served a 1.x, no tag was ever cut, and the one consumer resolves the working tree.
7
7
  # Publishing from 1.2.0 would have implied two releases nobody can install.
8
- VERSION = "1.8.1"
8
+ VERSION = "1.10.0"
9
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rail0-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.1
4
+ version: 1.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Commerce Layer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-28 00:00:00.000000000 Z
11
+ date: 2026-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logger
@@ -45,6 +45,7 @@ files:
45
45
  - lib/rail0/error_hints.rb
46
46
  - lib/rail0/http_client.rb
47
47
  - lib/rail0/payload_verify.rb
48
+ - lib/rail0/payout_verify.rb
48
49
  - lib/rail0/request.rb
49
50
  - lib/rail0/resources/accounts.rb
50
51
  - lib/rail0/resources/analytics.rb
@@ -54,6 +55,8 @@ files:
54
55
  - lib/rail0/resources/health.rb
55
56
  - lib/rail0/resources/payment_methods.rb
56
57
  - lib/rail0/resources/payments.rb
58
+ - lib/rail0/resources/payout_destinations.rb
59
+ - lib/rail0/resources/payouts.rb
57
60
  - lib/rail0/resources/query.rb
58
61
  - lib/rail0/resources/tokens.rb
59
62
  - lib/rail0/resources/wallets.rb