AhoSdk Ruby SDK
Official Ruby SDK for the Aho Verifiable Credentials API.
Installation
Add to your Gemfile:
gem 'aho-sdk'
Or install directly:
gem install aho-sdk
Quick Start
require 'aho-sdk'
# Initialize the Issuer client
issuer = AhoSdk::Issuer.new(api_key: ENV['AHO_ISSUER_API_KEY'])
# Issue a credential
credential = issuer.credentials.create(
schema_uuid: 'your-schema-uuid',
subject_identifier: 'user@example.com',
claims: {
name: 'Jane Doe',
role: 'Engineer'
}
)
puts credential['uuid']
Clients
The SDK provides the following clients:
| Client | Purpose | API Key Type |
|---|---|---|
AhoSdk::Account |
Manage account settings, domains, and API keys | Account API Key |
AhoSdk::System |
System health and status endpoints | System API Key |
AhoSdk::Holder |
Manage holder credentials and presentations | Holder API Key |
AhoSdk::Verifier |
Create presentation requests and verify credentials | Verifier API Key |
AhoSdk::Issuer |
Issue and manage verifiable credentials | Issuer API Key |
AhoSdk::Schemas |
Browse and retrieve credential schemas | Schemas API Key |
AhoSdk::Unauthenticated |
Public endpoints (no authentication required) | None (public) |
Usage Examples
Issuing Credentials
issuer = AhoSdk::Issuer.new(api_key: ENV['AHO_ISSUER_API_KEY'])
# List all schemas
schemas = issuer.schemas.list
schemas.data.each { |s| puts s['name'] }
# Create a schema
schema = issuer.schemas.create(
name: 'EmployeeBadge',
claims: [
{ name: 'employee_id', type: 'string', required: true },
{ name: 'department', type: 'string', required: true },
{ name: 'hire_date', type: 'date', required: false }
]
)
# Issue a credential
credential = issuer.credentials.create(
schema_uuid: schema['uuid'],
subject_identifier: 'jane.doe@company.com',
claims: {
employee_id: 'EMP-12345',
department: 'Engineering',
hire_date: '2024-01-15'
}
)
# Revoke a credential
issuer.credentials.revoke(uuid: credential['uuid'], reason: 'Employee departed')
Verifying Credentials
verifier = AhoSdk::Verifier.new(api_key: ENV['AHO_VERIFIER_API_KEY'])
# Create a presentation request
request = verifier.requests.create(
name: 'Employment Verification',
query_format: 'dcql',
credentials: [
{
id: 'employee_badge',
format: 'vc+sd-jwt',
claims: [
{ path: ['employee_id'] },
{ path: ['department'] }
]
}
]
)
# Get the QR code for the request (supports :png, :svg formats)
qr = verifier.requests.qr_code(uuid: request['uuid'], output_format: :svg)
# List responses to the request
responses = verifier.responses.list(request_uuid: request['uuid'])
Managing Holder Credentials
holder = AhoSdk::Holder.new(api_key: ENV['AHO_HOLDER_API_KEY'])
# List credentials
credentials = holder.credentials.list(status: 'active')
# Create a presentation (selective disclosure)
presentation = holder.presentations.create(
credential_uuid: 'credential-uuid',
disclosed_claims: ['name', 'department']
)
Account Management
account = AhoSdk::Account.new(api_key: ENV['AHO_API_KEY'])
# Manage domains
domains = account.domains.list
account.domains.verify(id: domain['id'])
# Manage signing keys
keys = account.signing_keys.list
account.signing_keys.rotate(id: key['id'])
# Configure webhooks
account.webhooks.create(
url: 'https://your-app.com/webhooks/aho',
events: ['credential.issued', 'credential.revoked']
)
Pagination
List methods return Page objects with built-in iteration:
# Iterate through all pages automatically
issuer.credentials.list.each do |credential|
puts credential['uuid']
end
# Or handle pages manually
page = issuer.credentials.list(per_page: 50)
while page
page.data.each { |c| puts c['uuid'] }
page = page.next_page
end
# Collect all items
all_credentials = issuer.credentials.list.to_a
File Uploads
For endpoints that accept file uploads:
# Upload a file
issuer.media.upload(
file: File.open('document.pdf'),
metadata: { description: 'Employee contract' }
)
# The SDK auto-detects MIME types from file extensions
# You can also pass a path string:
issuer.media.upload(file: '/path/to/document.pdf')
Binary Responses
Some endpoints return binary data (images, PDFs):
# Get QR code as PNG
png_data = verifier.requests.qr_code(uuid: '...', output_format: :png)
File.binwrite('qr.png', png_data)
# Get QR code as SVG
svg_data = verifier.requests.qr_code(uuid: '...', output_format: :svg)
File.write('qr.svg', svg_data)
Error Handling
begin
issuer.credentials.create(invalid_params)
rescue AhoSdk::ValidationError => e
# 422 - Validation failed
e.field_errors.each do |error|
puts "#{error['field']}: #{error['hint']}"
end
rescue AhoSdk::AuthenticationError => e
# 401 - Invalid API key
puts "Check your API key"
rescue AhoSdk::NotFoundError => e
# 404 - Resource not found
puts "Resource not found: #{e.}"
rescue AhoSdk::RateLimitError => e
# 429 - Rate limited (SDK auto-retries with exponential backoff)
puts "Retry after #{e.retry_after} seconds"
rescue AhoSdk::ApiError => e
# Other API errors
puts "Error #{e.status_code}: #{e.}"
puts "Request ID: #{e.request_id}"
end
Error Classes
| Error Class | HTTP Status | Description |
|---|---|---|
AuthenticationError |
401 | Invalid or missing API key |
ForbiddenError |
403 | Insufficient permissions |
NotFoundError |
404 | Resource not found |
ConflictError |
409 | Resource conflict |
ValidationError |
422 | Request validation failed |
RateLimitError |
429 | Rate limit exceeded |
ServerError |
5xx | Server-side error |
NetworkError |
- | Connection/timeout error |
ApiError |
* | Base class for all API errors |
Rate Limiting
The SDK automatically handles rate limits with exponential backoff:
- Idempotent methods (GET, DELETE, PUT): Auto-retry up to 3 times
- Non-idempotent methods (POST, PATCH): Only retry with idempotency key
# Use idempotency keys for safe retries on POST/PATCH
issuer.credentials.create(
schema_uuid: '...',
claims: { ... },
idempotency_key: 'unique-request-id'
)
Configuration
# Custom configuration
issuer = AhoSdk::Issuer.new(
api_key: ENV['AHO_ISSUER_API_KEY'],
base_url: 'https://api.aho.com', # Custom base URL
timeout: 60, # Request timeout in seconds
logger: Logger.new(STDOUT) # Enable debug logging
)
Requirements
- Ruby 3.1+
License
MIT