verifyo 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ac05704ce88ba45eb262a5d4f80fa8ce3de8570a031590ec2fe23db8cb5d7099
4
+ data.tar.gz: f624b01558f456ee7ab2dbe8eb1fec3969d6bcdd50dc56e832685d1b4b20ca5e
5
+ SHA512:
6
+ metadata.gz: 912764228a110380dfebc7584733845b04e33dd25d3fdef548f8ea16c4bd24b69769ae4790cdbc3de95006a6da76f9eb957e2a0a2deeb62ab93d6f44e36a74c1
7
+ data.tar.gz: de0db4d12fe9a280c5551317677e4d1c3600a5af6e34d2d7002bceea45ef17ece8daf08896da89895fc50107cda7751d3fd573a7e16c8121b141d0384e7d1511
data/CHANGELOG.md ADDED
@@ -0,0 +1,46 @@
1
+ # Changelog
2
+
3
+ All notable changes to the Verifyo Ruby SDK will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.0.0] - 2025-01-12
9
+
10
+ ### Added
11
+ - Initial release of Verifyo Ruby SDK
12
+ - Support for Ruby 2.7.0 and higher
13
+ - `Verifyo::Client` class with `check_address` method
14
+ - Comprehensive error handling with specific exception types:
15
+ - `AuthenticationError` for invalid API keys
16
+ - `RateLimitError` with usage metrics
17
+ - `ApiError` for general API errors
18
+ - `NetworkError` for connectivity issues
19
+ - Ruby-idiomatic models with `?` methods:
20
+ - `CheckResponse` - Main response wrapper
21
+ - `VerificationResult` - Individual verification with convenience methods
22
+ - `WalletInfo` - Wallet risk assessment
23
+ - `AmlScreening` - AML compliance results
24
+ - `RateLimitInfo` - Rate limit tracking
25
+ - Configuration management with global settings support
26
+ - Computed properties for common compliance checks:
27
+ - `verified?` - Check if user has completed KYC
28
+ - `meets_basic_requirements?` - Verify user meets all compliance requirements
29
+ - `suitable_for_age_restricted_services?` - Check for 21+ services
30
+ - `passes_aml_screening?` - Verify AML compliance
31
+ - `safe_to_interact?` - Check wallet safety
32
+ - Example applications and usage patterns
33
+ - Comprehensive documentation
34
+
35
+ ### Features
36
+ - Zero-Knowledge KYC verification
37
+ - Multi-chain wallet support
38
+ - AML/PEP screening results
39
+ - Age verification (18+ and 21+)
40
+ - Wallet risk assessment
41
+ - Document country verification
42
+ - Debug mode for development
43
+ - Rate limit monitoring and warnings
44
+ - Rails-ready integration
45
+
46
+ [1.0.0]: https://github.com/verifyo-dot-com/verifyo-ruby-sdk/releases/tag/v1.0.0
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Verifyo.com
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,402 @@
1
+ # Verifyo Ruby SDK
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/verifyo.svg)](https://badge.fury.io/rb/verifyo)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ Official Ruby SDK for the [Verifyo](https://verifyo.com) Zero-Knowledge KYC API. Verify wallet addresses for KYC compliance without exposing user personal data.
7
+
8
+ ## Features
9
+
10
+ - ✅ **Zero-Knowledge Verification** - Check KYC status without accessing personal data
11
+ - 🔒 **Type-Safe** - Comprehensive error handling with specific exception types
12
+ - ⚡ **Lightweight** - Minimal dependencies, uses Faraday for HTTP
13
+ - 📊 **Rate Limit Monitoring** - Built-in rate limit tracking and warnings
14
+ - 🎯 **Ruby Idioms** - Follows Ruby conventions with `?` methods and snake_case
15
+ - 🚀 **Rails Ready** - Easy integration with Ruby on Rails applications
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ ```ruby
22
+ gem 'verifyo'
23
+ ```
24
+
25
+ And then execute:
26
+
27
+ ```bash
28
+ bundle install
29
+ ```
30
+
31
+ Or install it yourself:
32
+
33
+ ```bash
34
+ gem install verifyo
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ ```ruby
40
+ require 'verifyo'
41
+
42
+ # Initialize the client
43
+ client = Verifyo::Client.new('vfy_sk_your_api_key')
44
+
45
+ # Check a wallet address
46
+ response = client.check_address('0x742d35...', network: 'ethereum')
47
+
48
+ if response.has_results?
49
+ verification = response.first_result
50
+
51
+ if verification.meets_basic_requirements?
52
+ puts "✅ User is KYC verified"
53
+ puts "KYC Level: #{verification.kyc_level}"
54
+ puts "Country: #{verification.document_country}"
55
+ end
56
+ end
57
+ ```
58
+
59
+ ## Configuration
60
+
61
+ ### Direct Initialization
62
+
63
+ ```ruby
64
+ client = Verifyo::Client.new(
65
+ 'vfy_sk_your_api_key',
66
+ base_url: 'https://api.verifyo.com', # Optional
67
+ timeout: 30, # Optional (seconds)
68
+ debug: true # Optional
69
+ )
70
+ ```
71
+
72
+ ### Global Configuration
73
+
74
+ ```ruby
75
+ # config/initializers/verifyo.rb (Rails)
76
+ Verifyo.configure do |config|
77
+ config.api_key = ENV['VERIFYO_API_KEY']
78
+ config.timeout = 30
79
+ config.debug = Rails.env.development?
80
+ end
81
+
82
+ # Then use without API key
83
+ client = Verifyo::Client.new(nil) # Uses global config
84
+ ```
85
+
86
+ ## API Methods
87
+
88
+ ### check_address
89
+
90
+ Check KYC verification status for a wallet address:
91
+
92
+ ```ruby
93
+ # Check with network specification
94
+ response = client.check_address(
95
+ '0x742d35...',
96
+ network: 'ethereum' # Optional
97
+ )
98
+
99
+ # Check without network (auto-detection)
100
+ response = client.check_address('3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy')
101
+ ```
102
+
103
+ ## Response Structure
104
+
105
+ ### CheckResponse
106
+
107
+ The main response wrapper:
108
+
109
+ ```ruby
110
+ if response.has_results?
111
+ puts "Found #{response.result_count} verification(s)"
112
+
113
+ response.results.each do |result|
114
+ # Process each verification
115
+ end
116
+ end
117
+
118
+ # Check rate limits
119
+ if response.rate_limit_info
120
+ rate_limit = response.rate_limit_info
121
+ puts "API Usage: #{rate_limit.used}/#{rate_limit.limit}"
122
+
123
+ if rate_limit.near_limit?
124
+ puts "⚠️ Approaching rate limit!"
125
+ end
126
+ end
127
+ ```
128
+
129
+ ### VerificationResult
130
+
131
+ Individual verification details:
132
+
133
+ ```ruby
134
+ verification = response.first_result
135
+
136
+ # Basic properties
137
+ puts "Status: #{verification.kyc_status}"
138
+ puts "Level: #{verification.kyc_level}"
139
+ puts "Country: #{verification.document_country || 'Not provided'}"
140
+
141
+ # Age verification (Ruby style with ? methods)
142
+ puts "Over 18: #{verification.age_over_18?}"
143
+ puts "Over 21: #{verification.age_over_21?}"
144
+
145
+ # Convenience methods
146
+ if verification.verified?
147
+ puts "User has completed KYC"
148
+ end
149
+
150
+ if verification.meets_basic_requirements?
151
+ # User is verified, 18+, passes AML, and wallet is safe
152
+ puts "User meets all basic compliance requirements"
153
+ end
154
+
155
+ if verification.suitable_for_age_restricted_services?
156
+ # User is 21+ and not barred
157
+ puts "Suitable for gambling/alcohol services"
158
+ end
159
+ ```
160
+
161
+ ### Wallet Information
162
+
163
+ ```ruby
164
+ wallet = verification.wallet
165
+
166
+ puts "Address: #{wallet.address}"
167
+ puts "Ownership: #{wallet.ownership_status}"
168
+ puts "Sanctioned: #{wallet.sanctioned?}"
169
+ puts "High Risk: #{wallet.high_risk?}"
170
+
171
+ if wallet.safe_to_interact?
172
+ puts "✅ Wallet is safe for transactions"
173
+ end
174
+ ```
175
+
176
+ ### AML Screening
177
+
178
+ ```ruby
179
+ aml = verification.aml
180
+
181
+ puts "Sanctioned: #{aml.sanctioned?}"
182
+ puts "PEP: #{aml.pep?}"
183
+ puts "Criminal: #{aml.criminal?}"
184
+ puts "Adverse Media: #{aml.adverse_media?}"
185
+
186
+ if aml.passes_aml_screening?
187
+ puts "✅ Passes all AML checks"
188
+ end
189
+
190
+ if aml.clean?
191
+ puts "✅ No flags at all"
192
+ end
193
+ ```
194
+
195
+ ## Error Handling
196
+
197
+ The SDK provides specific exception types for different error scenarios:
198
+
199
+ ```ruby
200
+ begin
201
+ response = client.check_address(address)
202
+
203
+ rescue Verifyo::AuthenticationError => e
204
+ # Invalid API key or authentication failure
205
+ puts "Authentication failed: #{e.message}"
206
+
207
+ rescue Verifyo::RateLimitError => e
208
+ # Rate limit exceeded
209
+ puts "Rate limit exceeded. Usage: #{e.used}/#{e.limit}"
210
+ puts "Tier: #{e.tier}"
211
+ puts "Resets at: #{e.resets_at}" if e.resets_at
212
+
213
+ rescue Verifyo::ApiError => e
214
+ # General API error
215
+ puts "API error (HTTP #{e.status_code}): #{e.message}"
216
+
217
+ rescue Verifyo::NetworkError => e
218
+ # Network connectivity issues
219
+ puts "Network error: #{e.message}"
220
+ end
221
+ ```
222
+
223
+ ## Examples
224
+
225
+ ### Exchange Integration
226
+
227
+ ```ruby
228
+ def can_user_trade?(wallet_address)
229
+ response = @verifyo_client.check_address(wallet_address)
230
+
231
+ return false unless response.has_results?
232
+
233
+ verification = response.first_result
234
+
235
+ # Check trading requirements
236
+ verification.verified? &&
237
+ verification.age_over_18? &&
238
+ verification.aml.passes_aml_screening? &&
239
+ verification.wallet.safe_to_interact?
240
+
241
+ rescue Verifyo::Error => e
242
+ Rails.logger.error "Verifyo error: #{e.message}"
243
+ false # Fail-safe: deny access on error
244
+ end
245
+ ```
246
+
247
+ ### Age-Restricted Services
248
+
249
+ ```ruby
250
+ def can_access_gambling?(wallet_address)
251
+ response = @verifyo_client.check_address(wallet_address)
252
+
253
+ return false unless response.has_results?
254
+
255
+ verification = response.first_result
256
+
257
+ # Most gambling services require 21+
258
+ verification.verified? &&
259
+ verification.age_over_21? &&
260
+ !verification.aml.barred?
261
+ end
262
+ ```
263
+
264
+ ### Batch Verification
265
+
266
+ ```ruby
267
+ def verify_multiple_wallets(addresses)
268
+ results = {}
269
+
270
+ addresses.each do |address|
271
+ begin
272
+ response = @verifyo_client.check_address(address)
273
+ results[address] = {
274
+ verified: response.has_verified_result?,
275
+ level: response.first_result&.kyc_level || 0,
276
+ country: response.first_result&.document_country
277
+ }
278
+
279
+ rescue Verifyo::RateLimitError
280
+ # Handle rate limiting gracefully
281
+ sleep 10
282
+ retry
283
+
284
+ rescue Verifyo::Error => e
285
+ results[address] = { error: e.message }
286
+ end
287
+ end
288
+
289
+ results
290
+ end
291
+ ```
292
+
293
+ ### Rails Controller Integration
294
+
295
+ ```ruby
296
+ class VerificationController < ApplicationController
297
+ before_action :initialize_verifyo_client
298
+
299
+ def check
300
+ response = @client.check_address(params[:address])
301
+
302
+ if response.has_results?
303
+ verification = response.first_result
304
+
305
+ render json: {
306
+ verified: verification.verified?,
307
+ kyc_level: verification.kyc_level,
308
+ meets_requirements: verification.meets_basic_requirements?,
309
+ country: verification.document_country
310
+ }
311
+ else
312
+ render json: {
313
+ verified: false,
314
+ message: 'No KYC verification found'
315
+ }, status: :not_found
316
+ end
317
+
318
+ rescue Verifyo::AuthenticationError
319
+ render json: { error: 'Invalid API credentials' }, status: :unauthorized
320
+
321
+ rescue Verifyo::RateLimitError => e
322
+ response.headers['X-RateLimit-Limit'] = e.limit.to_s
323
+ response.headers['X-RateLimit-Remaining'] = e.remaining.to_s
324
+ render json: { error: 'Rate limit exceeded' }, status: :too_many_requests
325
+
326
+ rescue Verifyo::Error => e
327
+ render json: { error: e.message }, status: :bad_request
328
+ end
329
+
330
+ private
331
+
332
+ def initialize_verifyo_client
333
+ @client = Verifyo::Client.new(Rails.application.credentials.verifyo_api_key)
334
+ end
335
+ end
336
+ ```
337
+
338
+ ### Background Job Processing
339
+
340
+ ```ruby
341
+ class KycVerificationJob < ApplicationJob
342
+ queue_as :default
343
+
344
+ def perform(wallet_address)
345
+ client = Verifyo::Client.new(ENV['VERIFYO_API_KEY'])
346
+ response = client.check_address(wallet_address)
347
+
348
+ if response.has_results?
349
+ verification = response.first_result
350
+
351
+ # Update user record
352
+ user = User.find_by(wallet_address: wallet_address)
353
+ user.update!(
354
+ kyc_verified: verification.verified?,
355
+ kyc_level: verification.kyc_level,
356
+ kyc_country: verification.document_country,
357
+ age_verified_18: verification.age_over_18?,
358
+ age_verified_21: verification.age_over_21?,
359
+ aml_passed: verification.aml.passes_aml_screening?
360
+ )
361
+ end
362
+
363
+ rescue Verifyo::Error => e
364
+ Rails.logger.error "KYC verification failed for #{wallet_address}: #{e.message}"
365
+ raise # Retry the job
366
+ end
367
+ end
368
+ ```
369
+
370
+ ## Rails Generator (Coming Soon)
371
+
372
+ Generate an initializer:
373
+
374
+ ```bash
375
+ rails generate verifyo:install
376
+ ```
377
+
378
+ This will create `config/initializers/verifyo.rb` with configuration template.
379
+
380
+ ## Best Practices
381
+
382
+ 1. **Use Environment Variables**: Store API keys in environment variables
383
+ 2. **Handle Rate Limits**: Implement exponential backoff when hitting rate limits
384
+ 3. **Fail-Safe**: Always deny access when verification fails or errors occur
385
+ 4. **Monitor Usage**: Check `rate_limit_info` to avoid hitting limits
386
+ 5. **Cache Results**: Consider caching verification results to reduce API calls
387
+ 6. **Log Errors**: Log all exceptions for debugging and monitoring
388
+
389
+ ## Requirements
390
+
391
+ - Ruby 2.7.0 or higher
392
+ - Valid Verifyo API key (starting with `vfy_sk_`)
393
+
394
+ ## Support
395
+
396
+ - Documentation: https://verifyo.com/docs
397
+ - Email: support@verifyo.com
398
+ - GitHub Issues: https://github.com/verifyo-dot-com/verifyo-ruby-sdk/issues
399
+
400
+ ## License
401
+
402
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,188 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'json'
5
+
6
+ module Verifyo
7
+ # Main Verifyo SDK client for KYC verification checks
8
+ class Client
9
+ SDK_VERSION = VERSION
10
+
11
+ attr_reader :api_key, :base_url, :timeout, :debug
12
+
13
+ # Initialize a new Verifyo client
14
+ #
15
+ # @param api_key [String] Your Verifyo secret API key (must start with 'vfy_sk_')
16
+ # @param base_url [String] API base URL (defaults to https://api.verifyo.com)
17
+ # @param timeout [Integer] Request timeout in seconds (defaults to 30)
18
+ # @param debug [Boolean] Enable debug logging
19
+ #
20
+ # @raise [ArgumentError] if API key is invalid
21
+ def initialize(api_key, base_url: nil, timeout: nil, debug: false)
22
+ # Support configuration from global settings
23
+ config = Verifyo.configuration
24
+
25
+ @api_key = api_key || config&.api_key
26
+ @base_url = base_url || config&.base_url || Configuration::DEFAULT_BASE_URL
27
+ @timeout = timeout || config&.timeout || Configuration::DEFAULT_TIMEOUT
28
+ @debug = debug || config&.debug || false
29
+
30
+ validate_api_key!
31
+ setup_connection
32
+ end
33
+
34
+ # Check KYC verification status for a wallet address
35
+ #
36
+ # @param address [String] Wallet address to check
37
+ # @param network [String, nil] Optional blockchain network (e.g., 'ethereum', 'bitcoin')
38
+ #
39
+ # @return [Models::CheckResponse] verification results and rate limit info
40
+ #
41
+ # @raise [AuthenticationError] if API key is invalid (401)
42
+ # @raise [RateLimitError] if rate limit is exceeded (429)
43
+ # @raise [ApiError] for other API errors
44
+ # @raise [NetworkError] for connectivity issues
45
+ #
46
+ # @example Check a Bitcoin address
47
+ # response = client.check_address('3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy', network: 'bitcoin')
48
+ # if response.has_results?
49
+ # verification = response.first_result
50
+ # puts "KYC Level: #{verification.kyc_level}" if verification.verified?
51
+ # end
52
+ def check_address(address, network: nil)
53
+ raise ArgumentError, 'Address is required' if address.nil? || address.empty?
54
+
55
+ params = { address: address }
56
+ params[:network] = network if network
57
+
58
+ log_debug "Checking address: #{address} on network: #{network || 'auto-detect'}"
59
+
60
+ response = connection.get('/v1/check', params) do |req|
61
+ req.headers['Authorization'] = "Bearer #{api_key}"
62
+ end
63
+
64
+ log_debug "Response: #{response.status} - #{response.body}"
65
+
66
+ handle_response(response)
67
+ rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e
68
+ raise NetworkError.new("Network error: #{e.message}", error: e.class.name)
69
+ rescue StandardError => e
70
+ raise unless e.is_a?(Verifyo::Error)
71
+ raise e
72
+ end
73
+
74
+ private
75
+
76
+ def validate_api_key!
77
+ raise ArgumentError, 'API key is required' if api_key.nil? || api_key.empty?
78
+
79
+ unless api_key.start_with?('vfy_sk_')
80
+ raise ArgumentError, 'Invalid API key format. API key must start with "vfy_sk_"'
81
+ end
82
+ end
83
+
84
+ def setup_connection
85
+ @connection = Faraday.new(url: base_url) do |faraday|
86
+ faraday.request :json
87
+ faraday.response :json, content_type: /\bjson$/
88
+ faraday.adapter Faraday.default_adapter
89
+
90
+ faraday.options.timeout = timeout
91
+ faraday.options.open_timeout = timeout
92
+
93
+ faraday.headers['User-Agent'] = "verifyo-ruby-sdk/#{SDK_VERSION} (Ruby #{RUBY_VERSION})"
94
+ faraday.headers['Accept'] = 'application/json'
95
+ faraday.headers['Content-Type'] = 'application/json'
96
+ end
97
+ end
98
+
99
+ def connection
100
+ @connection
101
+ end
102
+
103
+ def handle_response(response)
104
+ # Extract rate limit info from headers
105
+ rate_limit_info = extract_rate_limit_info(response.headers)
106
+
107
+ case response.status
108
+ when 200
109
+ Models::CheckResponse.new(response.body, rate_limit_info)
110
+ when 401
111
+ raise AuthenticationError.new(
112
+ extract_error_message(response.body),
113
+ status_code: response.status
114
+ )
115
+ when 429
116
+ handle_rate_limit_error(response.body, rate_limit_info)
117
+ when 400..499
118
+ raise ApiError.new(
119
+ extract_error_message(response.body),
120
+ response.status,
121
+ response_body: response.body
122
+ )
123
+ when 500..599
124
+ raise ApiError.new(
125
+ "Server error: #{extract_error_message(response.body)}",
126
+ response.status,
127
+ response_body: response.body
128
+ )
129
+ else
130
+ raise ApiError.new(
131
+ "Unexpected response: #{response.status}",
132
+ response.status,
133
+ response_body: response.body
134
+ )
135
+ end
136
+ end
137
+
138
+ def extract_rate_limit_info(headers)
139
+ return nil unless headers['x-ratelimit-limit']
140
+
141
+ Models::RateLimitInfo.new(
142
+ limit: headers['x-ratelimit-limit'].to_i,
143
+ used: headers['x-ratelimit-used'].to_i,
144
+ remaining: headers['x-ratelimit-remaining'].to_i,
145
+ tier: headers['x-ratelimit-tier'] || 'unknown'
146
+ )
147
+ end
148
+
149
+ def handle_rate_limit_error(body, rate_limit_info)
150
+ message = extract_error_message(body)
151
+
152
+ if rate_limit_info
153
+ raise RateLimitError.new(
154
+ message,
155
+ limit: rate_limit_info.limit,
156
+ used: rate_limit_info.used,
157
+ remaining: rate_limit_info.remaining,
158
+ tier: rate_limit_info.tier,
159
+ resets_at: body.dig('resets_at'),
160
+ context: { response_body: body }
161
+ )
162
+ else
163
+ # Fallback if headers are missing
164
+ raise RateLimitError.new(
165
+ message,
166
+ limit: body.dig('limit') || 0,
167
+ used: body.dig('used') || 0,
168
+ remaining: body.dig('remaining') || 0,
169
+ tier: body.dig('tier') || 'unknown',
170
+ resets_at: body.dig('resets_at'),
171
+ context: { response_body: body }
172
+ )
173
+ end
174
+ end
175
+
176
+ def extract_error_message(body)
177
+ return 'Unknown error' unless body.is_a?(Hash)
178
+
179
+ body.dig('error', 'message') || body['message'] || 'API error occurred'
180
+ end
181
+
182
+ def log_debug(message)
183
+ return unless debug
184
+
185
+ puts "[Verifyo SDK] #{message}"
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Verifyo
4
+ # Configuration class for SDK settings
5
+ class Configuration
6
+ DEFAULT_BASE_URL = 'https://api.verifyo.com'
7
+ DEFAULT_TIMEOUT = 30
8
+
9
+ attr_accessor :api_key, :base_url, :timeout, :debug
10
+
11
+ def initialize
12
+ @api_key = nil
13
+ @base_url = DEFAULT_BASE_URL
14
+ @timeout = DEFAULT_TIMEOUT
15
+ @debug = false
16
+ end
17
+
18
+ # Validate configuration
19
+ def validate!
20
+ raise ArgumentError, 'API key is required' if api_key.nil? || api_key.empty?
21
+
22
+ unless api_key.start_with?('vfy_sk_')
23
+ raise ArgumentError, 'Invalid API key format. API key must start with "vfy_sk_"'
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Verifyo
4
+ # Base error class for all Verifyo SDK errors
5
+ class Error < StandardError
6
+ attr_reader :context
7
+
8
+ def initialize(message = nil, context = {})
9
+ super(message)
10
+ @context = context
11
+ end
12
+ end
13
+
14
+ # Raised when authentication fails (401)
15
+ class AuthenticationError < Error
16
+ def initialize(message = 'Authentication failed. Please check your API key', context = {})
17
+ super(message, context)
18
+ end
19
+ end
20
+
21
+ # Raised when rate limit is exceeded (429)
22
+ class RateLimitError < Error
23
+ attr_reader :limit, :used, :remaining, :tier, :resets_at
24
+
25
+ def initialize(message, limit:, used:, remaining:, tier:, resets_at: nil, context: {})
26
+ super(message, context)
27
+ @limit = limit
28
+ @used = used
29
+ @remaining = remaining
30
+ @tier = tier
31
+ @resets_at = resets_at
32
+ end
33
+ end
34
+
35
+ # Raised for general API errors
36
+ class ApiError < Error
37
+ attr_reader :status_code
38
+
39
+ def initialize(message, status_code, context = {})
40
+ super(message, context)
41
+ @status_code = status_code
42
+ end
43
+ end
44
+
45
+ # Raised for network connectivity issues
46
+ class NetworkError < Error
47
+ def initialize(message = 'Network error occurred', context = {})
48
+ super(message, context)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Verifyo
4
+ module Models
5
+ # AML (Anti-Money Laundering) screening results
6
+ class AmlScreening
7
+ attr_reader :sanctioned, :pep, :criminal, :barred, :military, :adverse_media
8
+
9
+ def initialize(data)
10
+ @sanctioned = data['sanctioned'] || false
11
+ @pep = data['pep'] || false
12
+ @criminal = data['criminal'] || false
13
+ @barred = data['barred'] || false
14
+ @military = data['military'] || false
15
+ @adverse_media = data['adverse_media'] || false
16
+ end
17
+
18
+ # Check if user passes all AML screening checks
19
+ def passes_aml_screening?
20
+ !sanctioned && !criminal && !barred
21
+ end
22
+
23
+ # Check if user has any high-risk flags
24
+ def high_risk?
25
+ sanctioned || criminal || barred
26
+ end
27
+
28
+ # Check if user has any flags at all
29
+ def clean?
30
+ !sanctioned && !pep && !criminal && !barred && !military && !adverse_media
31
+ end
32
+
33
+ # Alias methods for Ruby convention
34
+ alias sanctioned? sanctioned
35
+ alias pep? pep
36
+ alias criminal? criminal
37
+ alias barred? barred
38
+ alias military? military
39
+ alias adverse_media? adverse_media
40
+
41
+ def to_h
42
+ {
43
+ sanctioned: sanctioned,
44
+ pep: pep,
45
+ criminal: criminal,
46
+ barred: barred,
47
+ military: military,
48
+ adverse_media: adverse_media
49
+ }
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Verifyo
4
+ module Models
5
+ # Main response wrapper for KYC verification check
6
+ class CheckResponse
7
+ attr_reader :results, :rate_limit_info
8
+
9
+ def initialize(data, rate_limit_info = nil)
10
+ @results = (data['results'] || []).map { |result| VerificationResult.new(result) }
11
+ @rate_limit_info = rate_limit_info
12
+ end
13
+
14
+ # Check if any verification results were found
15
+ def has_results?
16
+ !results.empty?
17
+ end
18
+
19
+ # Get the first verification result
20
+ def first_result
21
+ results.first
22
+ end
23
+
24
+ # Get the number of verification results
25
+ def result_count
26
+ results.length
27
+ end
28
+
29
+ # Check if any result is verified
30
+ def has_verified_result?
31
+ results.any?(&:verified?)
32
+ end
33
+
34
+ # Get only verified results
35
+ def verified_results
36
+ results.select(&:verified?)
37
+ end
38
+
39
+ # Check if approaching rate limit
40
+ def approaching_rate_limit?
41
+ rate_limit_info&.near_limit? || false
42
+ end
43
+
44
+ def to_h
45
+ {
46
+ results: results.map(&:to_h),
47
+ rate_limit_info: rate_limit_info&.to_h
48
+ }
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Verifyo
4
+ module Models
5
+ # Rate limit information from API response headers
6
+ class RateLimitInfo
7
+ attr_reader :limit, :used, :remaining, :tier
8
+
9
+ def initialize(limit:, used:, remaining:, tier:)
10
+ @limit = limit
11
+ @used = used
12
+ @remaining = remaining
13
+ @tier = tier
14
+ end
15
+
16
+ # Check if approaching rate limit (within 10%)
17
+ def near_limit?
18
+ return false if limit.zero?
19
+
20
+ (used.to_f / limit) > 0.9
21
+ end
22
+
23
+ # Percentage of rate limit used
24
+ def usage_percentage
25
+ return 0.0 if limit.zero?
26
+
27
+ (used.to_f / limit * 100).round(2)
28
+ end
29
+
30
+ def to_h
31
+ {
32
+ limit: limit,
33
+ used: used,
34
+ remaining: remaining,
35
+ tier: tier
36
+ }
37
+ end
38
+
39
+ def to_s
40
+ "#{used}/#{limit} (#{tier} tier)"
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Verifyo
4
+ module Models
5
+ # Individual KYC verification result for a wallet address
6
+ class VerificationResult
7
+ attr_reader :zk_kyc_token, :identity, :kyc_level, :kyc_status,
8
+ :document_country, :residence_country,
9
+ :age_over_18, :age_over_21, :wallet, :aml
10
+
11
+ def initialize(data)
12
+ @zk_kyc_token = data['zk_kyc_token'] || ''
13
+ @identity = data['identity'] || ''
14
+ @kyc_level = data['kyc_level'] || 0
15
+ @kyc_status = data['kyc_status'] || 'not_verified'
16
+ @document_country = data['document_country']
17
+ @residence_country = data['residence_country']
18
+ @age_over_18 = data['age_over_18'] || false
19
+ @age_over_21 = data['age_over_21'] || false
20
+ @wallet = WalletInfo.new(data['wallet'] || {})
21
+ @aml = AmlScreening.new(data['aml'] || {})
22
+ end
23
+
24
+ # Check if user is KYC verified
25
+ def verified?
26
+ kyc_status == 'verified'
27
+ end
28
+
29
+ # Check if user meets basic compliance requirements
30
+ # Returns true if user is:
31
+ # - KYC verified
32
+ # - Over 18 years old
33
+ # - Passes AML screening
34
+ # - Has safe wallet (not sanctioned, not high risk)
35
+ def meets_basic_requirements?
36
+ verified? && age_over_18? && aml.passes_aml_screening? && wallet.safe_to_interact?
37
+ end
38
+
39
+ # Check if suitable for age-restricted services (21+)
40
+ def suitable_for_age_restricted_services?
41
+ verified? && age_over_21? && !aml.barred?
42
+ end
43
+
44
+ # Check if user has enhanced KYC (Level 2+)
45
+ def enhanced_kyc?
46
+ kyc_level >= 2
47
+ end
48
+
49
+ # Check if user has full KYC (Level 3)
50
+ def full_kyc?
51
+ kyc_level >= 3
52
+ end
53
+
54
+ # Alias methods for Ruby convention
55
+ alias age_over_18? age_over_18
56
+ alias age_over_21? age_over_21
57
+
58
+ def to_h
59
+ {
60
+ zk_kyc_token: zk_kyc_token,
61
+ identity: identity,
62
+ kyc_level: kyc_level,
63
+ kyc_status: kyc_status,
64
+ document_country: document_country,
65
+ residence_country: residence_country,
66
+ age_over_18: age_over_18,
67
+ age_over_21: age_over_21,
68
+ wallet: wallet.to_h,
69
+ aml: aml.to_h
70
+ }
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Verifyo
4
+ module Models
5
+ # Wallet information and risk assessment
6
+ class WalletInfo
7
+ attr_reader :address, :ownership_status, :sanctioned, :high_risk
8
+
9
+ def initialize(data)
10
+ @address = data['address'] || ''
11
+ @ownership_status = data['ownership_status'] || 'unknown'
12
+ @sanctioned = data['sanctioned'] || false
13
+ @high_risk = data['high_risk'] || false
14
+ end
15
+
16
+ # Check if wallet is safe for transactions
17
+ def safe_to_interact?
18
+ !sanctioned && !high_risk
19
+ end
20
+
21
+ # Check if wallet ownership is verified
22
+ def ownership_verified?
23
+ ownership_status == 'verified'
24
+ end
25
+
26
+ # Check if wallet is self-declared
27
+ def self_declared?
28
+ ownership_status == 'self_declared'
29
+ end
30
+
31
+ # Alias methods for Ruby convention
32
+ alias sanctioned? sanctioned
33
+ alias high_risk? high_risk
34
+
35
+ def to_h
36
+ {
37
+ address: address,
38
+ ownership_status: ownership_status,
39
+ sanctioned: sanctioned,
40
+ high_risk: high_risk
41
+ }
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Verifyo
4
+ VERSION = '1.0.0'
5
+ end
data/lib/verifyo.rb ADDED
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'json'
5
+
6
+ require_relative 'verifyo/version'
7
+ require_relative 'verifyo/configuration'
8
+ require_relative 'verifyo/errors'
9
+ require_relative 'verifyo/models/rate_limit_info'
10
+ require_relative 'verifyo/models/aml_screening'
11
+ require_relative 'verifyo/models/wallet_info'
12
+ require_relative 'verifyo/models/verification_result'
13
+ require_relative 'verifyo/models/check_response'
14
+ require_relative 'verifyo/client'
15
+
16
+ # Main module for Verifyo SDK
17
+ module Verifyo
18
+ class << self
19
+ attr_accessor :configuration
20
+
21
+ # Configure the SDK
22
+ #
23
+ # @yield [Configuration] configuration object
24
+ # @example
25
+ # Verifyo.configure do |config|
26
+ # config.api_key = 'vfy_sk_your_api_key'
27
+ # config.timeout = 30
28
+ # end
29
+ def configure
30
+ self.configuration ||= Configuration.new
31
+ yield(configuration)
32
+ end
33
+
34
+ # Reset configuration to defaults
35
+ def reset_configuration!
36
+ self.configuration = Configuration.new
37
+ end
38
+ end
39
+ end
metadata ADDED
@@ -0,0 +1,187 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: verifyo
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Verifyo Team
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-09-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday-net_http
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '13.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '13.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: vcr
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '6.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '6.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: webmock
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: yard
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.9'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.9'
139
+ description: Verify wallet addresses for KYC compliance without exposing user personal
140
+ data. Check age verification, AML screening, and document verification status.
141
+ email:
142
+ - support@verifyo.com
143
+ executables: []
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - CHANGELOG.md
148
+ - LICENSE
149
+ - README.md
150
+ - lib/verifyo.rb
151
+ - lib/verifyo/client.rb
152
+ - lib/verifyo/configuration.rb
153
+ - lib/verifyo/errors.rb
154
+ - lib/verifyo/models/aml_screening.rb
155
+ - lib/verifyo/models/check_response.rb
156
+ - lib/verifyo/models/rate_limit_info.rb
157
+ - lib/verifyo/models/verification_result.rb
158
+ - lib/verifyo/models/wallet_info.rb
159
+ - lib/verifyo/version.rb
160
+ homepage: https://github.com/verifyo-dot-com/verifyo-ruby-sdk
161
+ licenses:
162
+ - MIT
163
+ metadata:
164
+ homepage_uri: https://github.com/verifyo-dot-com/verifyo-ruby-sdk
165
+ source_code_uri: https://github.com/verifyo-dot-com/verifyo-ruby-sdk
166
+ changelog_uri: https://github.com/verifyo-dot-com/verifyo-ruby-sdk/blob/main/CHANGELOG.md
167
+ documentation_uri: https://verifyo.com/docs
168
+ post_install_message:
169
+ rdoc_options: []
170
+ require_paths:
171
+ - lib
172
+ required_ruby_version: !ruby/object:Gem::Requirement
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: 2.7.0
177
+ required_rubygems_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ requirements: []
183
+ rubygems_version: 3.5.22
184
+ signing_key:
185
+ specification_version: 4
186
+ summary: Official Ruby SDK for Verifyo Zero-Knowledge KYC API
187
+ test_files: []