Class: OpenBankingIO::Client
- Inherits:
-
Object
- Object
- OpenBankingIO::Client
- Defined in:
- lib/open_banking_io/client.rb
Overview
Server-to-server client for open-banking.io.
Authenticates with an API key (X-Api-Key) and decrypts the zero-knowledge data envelopes locally with the exported private key – the service only ever returns ciphertext it cannot read.
Constant Summary collapse
- DEFAULT_OPEN_TIMEOUT =
15- DEFAULT_READ_TIMEOUT =
60
Class Method Summary collapse
-
.from_credentials(path_or_json) ⇒ Object
Builds a client from a credentials-bundle JSON string or a path to a bundle file.
Instance Method Summary collapse
-
#get_accounts ⇒ Object
Lists the user’s accounts with all sensitive fields decrypted.
-
#get_connections ⇒ Object
Lists the user’s bank connections.
-
#get_transactions(account_id, from: nil, to: nil, limit: nil, offset: nil) ⇒ Object
Returns a page of an account’s statement, newest first, with decrypted fields.
-
#initialize(api_base_url:, api_key:, private_key_pkcs8:) ⇒ Client
constructor
A new instance of Client.
-
#sync(account_id) ⇒ Object
Triggers an online sync of one account.
-
#sync_all ⇒ Object
Triggers an online sync of every account that has an active session.
Constructor Details
#initialize(api_base_url:, api_key:, private_key_pkcs8:) ⇒ Client
Returns a new instance of Client.
54 55 56 57 58 59 60 61 62 |
# File 'lib/open_banking_io/client.rb', line 54 def initialize(api_base_url:, api_key:, private_key_pkcs8:) raise ArgumentError, "api_base_url is required" if blank?(api_base_url) raise ArgumentError, "api_key is required" if blank?(api_key) raise ArgumentError, "private_key_pkcs8 is required" if blank?(private_key_pkcs8) @base_uri = URI.parse(api_base_url.to_s.sub(%r{/+\z}, "") + "/") @api_key = api_key @private_key = Envelope.load_private_key(private_key_pkcs8) end |
Class Method Details
.from_credentials(path_or_json) ⇒ Object
Builds a client from a credentials-bundle JSON string or a path to a bundle file.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/open_banking_io/client.rb', line 33 def self.from_credentials(path_or_json) raw = if File.file?(path_or_json.to_s) File.read(path_or_json) else path_or_json end bundle = JSON.parse(raw) api_base_url = bundle["apiBaseUrl"].to_s api_key = bundle["apiKey"] raise ArgumentError, "The credentials bundle has no apiKey" if api_key.nil? || api_key.empty? enc_key = bundle["encryptionKey"] || {} private_key = enc_key["privateKey"] || enc_key["privateKeyPkcs8B64"] if private_key.nil? || private_key.to_s.empty? raise ArgumentError, "The credentials bundle has no encryption private key" end new(api_base_url: api_base_url, api_key: api_key, private_key_pkcs8: private_key) end |
Instance Method Details
#get_accounts ⇒ Object
Lists the user’s accounts with all sensitive fields decrypted.
65 66 67 |
# File 'lib/open_banking_io/client.rb', line 65 def get_accounts account_wires.map { |w| map_account(w) } end |
#get_connections ⇒ Object
Lists the user’s bank connections.
83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/open_banking_io/client.rb', line 83 def get_connections get_json("api/connections").map do |c| Connection.new( session_id: c["sessionId"] || "", aspsp_name: c["aspspName"] || "", aspsp_country: c["aspspCountry"] || "", valid_until: c["validUntil"], status: c["status"] || "", account_count: c["accountCount"] || 0, last_synced_at: c["lastSyncedAt"], psu_type: c["psuType"] ) end end |
#get_transactions(account_id, from: nil, to: nil, limit: nil, offset: nil) ⇒ Object
Returns a page of an account’s statement, newest first, with decrypted fields.
70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/open_banking_io/client.rb', line 70 def get_transactions(account_id, from: nil, to: nil, limit: nil, offset: nil) params = {} params["from"] = from unless from.nil? params["to"] = to unless to.nil? params["limit"] = limit unless limit.nil? params["offset"] = offset unless offset.nil? page = get_json("api/accounts/#{account_id}/transactions", params) items = (page["items"] || []).map { |t| map_transaction(t) } TransactionPage.new(items: items, total: page["total"] || 0) end |
#sync(account_id) ⇒ Object
Triggers an online sync of one account.
Decrypts that account’s Enable Banking uid and posts it, so the service can fetch fresh data without ever holding the uid in plaintext.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/open_banking_io/client.rb', line 102 def sync(account_id) account = account_wires.find { |a| a["id"] == account_id } raise ArgumentError, "Account #{account_id} not found" if account.nil? uid = decrypt_uid(account) if uid.nil? raise ArgumentError, "Account has no active session (reconnect required) -- cannot sync" end result = post_json("api/accounts/#{account_id}/sync", { "uid" => uid }) SyncResult.new( new_transactions: result["newTransactions"] || 0, total_fetched: result["totalFetched"] || 0 ) end |
#sync_all ⇒ Object
Triggers an online sync of every account that has an active session.
119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/open_banking_io/client.rb', line 119 def sync_all items = [] account_wires.each do |a| uid = decrypt_uid(a) items << { "accountId" => a["id"], "uid" => uid } unless uid.nil? end result = post_json("api/sync", { "items" => items }) SyncAllResult.new( accounts: result["accounts"] || 0, new_transactions: result["newTransactions"] || 0 ) end |