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

 = AhoSdk::Account.new(api_key: ENV['AHO_API_KEY'])

# Manage domains
domains = .domains.list
.domains.verify(id: domain['id'])

# Manage signing keys
keys = .signing_keys.list
.signing_keys.rotate(id: key['id'])

# Configure webhooks
.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.message}"
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.message}"
  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