Skip to Content
SDKsRuby

Ruby SDK

An idiomatic Ruby client for the IdentityCall API with Rails integration support.

Installation

gem install httparty multipart-post # Or add to Gemfile gem 'httparty' gem 'multipart-post'

Quick Start

require_relative 'identitycall' client = IdentityCall::Client.new # List recordings result = client.recordings.list result['data'].each do |recording| puts "#{recording['id']}: #{recording['name']}" end

Complete Client Implementation

Create a file called identitycall.rb:

identitycall.rb
require 'net/http' require 'net/http/post/multipart' require 'json' require 'uri' module IdentityCall # Base exception class class Error < StandardError attr_reader :status_code, :response def initialize(message, status_code: nil, response: nil) @status_code = status_code @response = response super(message) end end class AuthenticationError < Error; end class PermissionError < Error; end class NotFoundError < Error; end class ValidationError < Error; end class RateLimitError < Error attr_reader :retry_after def initialize(message, retry_after: 60, **kwargs) @retry_after = retry_after super(message, **kwargs) end end # Recordings resource class Recordings def initialize(client) @client = client end def list(page: 1, per_page: 20) @client.request(:get, '/recordings', params: { page: page, per_page: per_page }) end def create(file_path, language: 'en', name: nil) @client.upload('/recordings', file_path, language: language, name: name) end def get(recording_id) @client.request(:get, "/recordings/#{recording_id}") end def update(recording_id, **data) @client.request(:patch, "/recordings/#{recording_id}", json: data) end def delete(recording_id) @client.request(:delete, "/recordings/#{recording_id}") end def transcription(recording_id) @client.request(:get, "/recordings/#{recording_id}/transcription") end def results(recording_id) @client.request(:get, "/recordings/#{recording_id}/results") end def summary(recording_id) @client.request(:get, "/recordings/#{recording_id}/summary") end def wait_for_completion(recording_id, timeout: 600, poll_interval: 5) start_time = Time.now loop do result = get(recording_id) recording = result['data'] return recording if recording['status'] == 'completed' raise Error.new('Transcription failed') if recording['status'] == 'failed' raise Timeout::Error, 'Transcription timed out' if Time.now - start_time > timeout sleep(poll_interval) end end end # Main client class Client DEFAULT_BASE_URL = 'https://api.identitycall.com/api/v1/public'.freeze MAX_RETRIES = 3 attr_reader :api_key, :base_url, :recordings def initialize(api_key: nil, base_url: nil, timeout: 30) @api_key = api_key || ENV['IDENTITYCALL_API_KEY'] raise ArgumentError, 'API key is required' unless @api_key @base_url = base_url || DEFAULT_BASE_URL @timeout = timeout @recordings = Recordings.new(self) end def request(method, path, params: nil, json: nil) uri = build_uri(path, params) http = build_http(uri) request = build_request(method, uri, json) with_retry do response = http.request(request) handle_response(response) end end def upload(path, file_path, language:, name: nil) uri = build_uri(path) http = build_http(uri) File.open(file_path) do |file| params = { 'file' => UploadIO.new(file, 'audio/mpeg', File.basename(file_path)), 'language' => language } params['name'] = name if name request = Net::HTTP::Post::Multipart.new(uri.path, params) request['Authorization'] = "Bearer #{@api_key}" request['Accept'] = 'application/json' with_retry do response = http.request(request) handle_response(response) end end end private def build_uri(path, params = nil) uri = URI.parse("#{@base_url}#{path}") uri.query = URI.encode_www_form(params) if params uri end def build_http(uri) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true http.read_timeout = @timeout http.open_timeout = @timeout http end def build_request(method, uri, json = nil) request_class = { get: Net::HTTP::Get, post: Net::HTTP::Post, patch: Net::HTTP::Patch, delete: Net::HTTP::Delete }[method] request = request_class.new(uri) request['Authorization'] = "Bearer #{@api_key}" request['Accept'] = 'application/json' if json request['Content-Type'] = 'application/json' request.body = JSON.generate(json) end request end def with_retry attempts = 0 begin attempts += 1 yield rescue RateLimitError => e if attempts < MAX_RETRIES sleep(e.retry_after) retry end raise rescue Error => e if e.status_code && e.status_code >= 500 && attempts < MAX_RETRIES sleep(2**attempts) retry end raise end end def handle_response(response) return nil if response.code == '204' data = response.body.to_s.empty? ? {} : JSON.parse(response.body) return data if response.is_a?(Net::HTTPSuccess) error_message = data['error'] || 'Unknown error' status_code = response.code.to_i raise_error(status_code, error_message, data) end def raise_error(status_code, message, data) case status_code when 401 raise AuthenticationError.new(message, status_code: status_code, response: data) when 403 raise PermissionError.new(message, status_code: status_code, response: data) when 404 raise NotFoundError.new(message, status_code: status_code, response: data) when 422 raise ValidationError.new(message, status_code: status_code, response: data) when 429 retry_after = data['retry_after'] || 60 raise RateLimitError.new(message, retry_after: retry_after, status_code: status_code, response: data) else raise Error.new(message, status_code: status_code, response: data) end end end end

Usage Examples

List Recordings

require_relative 'identitycall' client = IdentityCall::Client.new # Get first page result = client.recordings.list result['data'].each do |recording| puts "[#{recording['id']}] #{recording['name']} - #{recording['status']}" end # With pagination result = client.recordings.list(page: 2, per_page: 50) meta = result['meta'] puts "Page #{meta['current_page']} of #{meta['total_pages']}"

Upload Recording

result = client.recordings.create( '/path/to/call.mp3', language: 'en', name: 'Customer Support Call' ) recording_id = result['data']['id'] puts "Uploaded! Recording ID: #{recording_id}"

Wait for Transcription

# Upload result = client.recordings.create('/path/to/call.mp3') recording_id = result['data']['id'] # Wait for completion puts 'Processing...' recording = client.recordings.wait_for_completion(recording_id) puts "Completed! Duration: #{recording['duration_ms']}ms" # Get transcription transcription = client.recordings.transcription(recording_id) puts transcription['data']['full_text']

Get Analysis Results

results = client.recordings.results(recording_id) # Goals puts 'Goals:' results['data']['goals'].each do |goal| status = goal['met'] ? '✓' : '✗' puts " #{status} #{goal['goal_name']}: #{format('%.2f', goal['score'])}" end # Keywords puts "\nKeywords:" results['data']['keywords'].each do |kw| puts " \"#{kw['keyword_name']}\" - #{kw['count']} mentions" end

Error Handling

require_relative 'identitycall' client = IdentityCall::Client.new begin recording = client.recordings.get(999_999) rescue IdentityCall::NotFoundError puts 'Recording not found' rescue IdentityCall::PermissionError puts 'Permission denied' rescue IdentityCall::AuthenticationError puts 'Invalid API key' rescue IdentityCall::RateLimitError => e puts "Rate limited. Retry in #{e.retry_after} seconds" end

Iterate All Pages

def get_all_recordings(client) all_recordings = [] page = 1 per_page = 100 loop do result = client.recordings.list(page: page, per_page: per_page) all_recordings.concat(result['data']) meta = result['meta'] break if meta['current_page'] >= meta['total_pages'] page += 1 end all_recordings end # Usage recordings = get_all_recordings(client) puts "Total recordings: #{recordings.length}"

Enumerator Pattern

def each_recording(client, per_page: 100) return enum_for(:each_recording, client, per_page: per_page) unless block_given? page = 1 loop do result = client.recordings.list(page: page, per_page: per_page) result['data'].each { |recording| yield recording } meta = result['meta'] break if meta['current_page'] >= meta['total_pages'] page += 1 end end # Usage each_recording(client).each do |recording| puts recording['name'] end # Or with Enumerator methods each_recording(client).take(10).each { |r| process(r) }

Rails Integration

Initializer

config/initializers/identitycall.rb
require_relative '../../lib/identitycall' Rails.application.config.identitycall = IdentityCall::Client.new( api_key: Rails.application.credentials.identitycall_api_key, base_url: ENV.fetch('IDENTITYCALL_BASE_URL', 'https://api.identitycall.com/api/v1/public') )

Helper Method

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base private def identitycall Rails.application.config.identitycall end end

Controller Usage

app/controllers/recordings_controller.rb
class RecordingsController < ApplicationController def index result = identitycall.recordings.list(page: params[:page] || 1) @recordings = result['data'] @meta = result['meta'] end def show result = identitycall.recordings.get(params[:id]) @recording = result['data'] end def create if params[:file].present? result = identitycall.recordings.create( params[:file].tempfile.path, language: params[:language] || 'en', name: params[:name] ) redirect_to recording_path(result['data']['id']), notice: 'Recording uploaded!' else redirect_to new_recording_path, alert: 'Please select a file' end end end

Background Job

app/jobs/process_recording_job.rb
class ProcessRecordingJob < ApplicationJob queue_as :default def perform(recording_id) client = Rails.application.config.identitycall # Wait for transcription recording = client.recordings.wait_for_completion(recording_id, timeout: 600) # Get results results = client.recordings.results(recording_id) transcription = client.recordings.transcription(recording_id) # Store or process results RecordingResult.create!( external_id: recording_id, duration_ms: recording['duration_ms'], full_text: transcription['data']['full_text'], goals_met: results['data']['goals'].count { |g| g['met'] }, goals_total: results['data']['goals'].count ) end end

Gem Structure

For a full gem implementation:

identitycall-ruby/ ├── lib/ │ ├── identitycall.rb │ ├── identitycall/ │ │ ├── client.rb │ │ ├── resources/ │ │ │ └── recordings.rb │ │ ├── errors.rb │ │ └── version.rb ├── identitycall.gemspec ├── Gemfile └── README.md

Next Steps