Ruby Examples
Complete code examples for using the TakeTheme API with Ruby.
Setup
Using Net::HTTP
require 'net/http'
require 'json'
require 'uri'
class TakeThemeClient
BASE_URL = 'https://api.taketheme.com/api/v1'.freeze
def initialize(api_key)
@api_key = api_key
end
def get(endpoint, params = {})
uri = URI("#{BASE_URL}#{endpoint}")
uri.query = URI.encode_www_form(params) unless params.empty?
request(Net::HTTP::Get.new(uri))
end
def post(endpoint, data)
uri = URI("#{BASE_URL}#{endpoint}")
req = Net::HTTP::Post.new(uri)
req.body = data.to_json
request(req)
end
def patch(endpoint, data)
uri = URI("#{BASE_URL}#{endpoint}")
req = Net::HTTP::Patch.new(uri)
req.body = data.to_json
request(req)
end
def delete(endpoint)
uri = URI("#{BASE_URL}#{endpoint}")
request(Net::HTTP::Delete.new(uri))
end
private
def request(req)
req["tt-api-key"] = "#{@api_key}"
req['Content-Type'] = 'application/json'
uri = req.uri
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(req)
end
result = JSON.parse(response.body)
unless response.is_a?(Net::HTTPSuccess)
raise TakeThemeError.new(result['error'])
end
result
end
end
class TakeThemeError < StandardError
attr_reader :code, :status, :details, :request_id
def initialize(error)
@code = error['code']
@status = error['status']
@details = error['details'] || []
@request_id = error['request_id']
super(error['message'] || 'Unknown error')
end
end
# Initialize
client = TakeThemeClient.new(ENV['TAKETHEME_API_KEY'])
Using Faraday
gem install faraday
require 'faraday'
require 'json'
class TakeThemeFaradayClient
BASE_URL = 'https://api.taketheme.com/api/v1'.freeze
def initialize(api_key)
@conn = Faraday.new(url: BASE_URL) do |f|
f.request :json
f.response :json
f.adapter Faraday.default_adapter
f.headers['tt-api-key'] = "#{api_key}"
end
end
def get(endpoint, params = {})
response = @conn.get(endpoint, params)
handle_response(response)
end
def post(endpoint, data)
response = @conn.post(endpoint, data)
handle_response(response)
end
def patch(endpoint, data)
response = @conn.patch(endpoint, data)
handle_response(response)
end
def delete(endpoint)
response = @conn.delete(endpoint)
handle_response(response)
end
private
def handle_response(response)
unless response.success?
raise TakeThemeError.new(response.body['error'])
end
response.body
end
end
Products
List All Products
response = client.get('/products', limit: 25)
products = response['data']
pagination = response['pagination']
puts "Found #{pagination['total_count']} products"
products.each do |product|
puts "- #{product['title']} ($#{product['price']})"
end
Get a Single Product
product = client.get('/products/prod_abc123')['data']
puts "#{product['title']}: #{product['description']}"
Create a Product
new_product = client.post('/products', {
title: 'Premium Sneakers',
description: 'Comfortable running sneakers',
price: 89.99,
currency: 'USD',
status: 'active',
variants: [
{ title: 'Size 8', sku: 'SNEAKER-8', price: 89.99, inventory_quantity: 25 },
{ title: 'Size 9', sku: 'SNEAKER-9', price: 89.99, inventory_quantity: 30 },
{ title: 'Size 10', sku: 'SNEAKER-10', price: 89.99, inventory_quantity: 20 }
],
images: [
{ src: 'https://example.com/sneakers.jpg', alt: 'Premium Sneakers' }
]
})['data']
puts "Created product: #{new_product['id']}"
Update a Product
updated = client.patch('/products/prod_abc123', {
price: 94.99,
tags: ['featured', 'athletics']
})['data']
Delete a Product
client.delete('/products/prod_abc123')
Orders
List Orders
# Recent pending orders
orders = client.get('/orders', status: 'pending', limit: 50)['data']
# Orders from the last week
week_ago = (Time.now - 7 * 24 * 60 * 60).iso8601
recent_orders = client.get('/orders', created_at_min: week_ago)['data']
Create an Order
order = client.post('/orders', {
customer: {
email: 'customer@example.com',
first_name: 'John',
last_name: 'Doe'
},
line_items: [
{
variant_id: 'var_abc123',
quantity: 2,
price: 29.99
}
],
shipping_address: {
first_name: 'John',
last_name: 'Doe',
address1: '123 Main Street',
city: 'New York',
province: 'NY',
postal_code: '10001',
country: 'US',
phone: '+1-555-123-4567'
},
shipping_line: {
title: 'Standard Shipping',
price: 5.99
}
})['data']
puts "Order created: #{order['order_number']}"
Fulfill an Order
fulfillment = client.post("/orders/#{order_id}/fulfillments", {
line_items: [
{ id: 'li_abc123', quantity: 2 }
],
tracking_number: '1Z999AA10123456784',
tracking_company: 'UPS',
notify_customer: true
})['data']
Cancel an Order
cancelled = client.post("/orders/#{order_id}/cancel", {
reason: 'customer_request',
restock: true,
notify_customer: true
})['data']
Customers
Search Customers
# Find by email
customers = client.get('/customers', email: 'john@example.com')['data']
# Find VIP customers
vip_customers = client.get('/customers', tags: 'vip', orders_count_min: 10)['data']
Create a Customer
customer = client.post('/customers', {
email: 'newcustomer@example.com',
first_name: 'Jane',
last_name: 'Smith',
phone: '+1-555-987-6543',
addresses: [
{
address1: '456 Oak Avenue',
city: 'Los Angeles',
province: 'CA',
postal_code: '90001',
country: 'US',
default: true
}
],
tags: ['newsletter', 'loyalty-program'],
accepts_marketing: true
})['data']
Webhooks
Register a Webhook
webhook = client.post('/webhooks', {
topic: 'orders/created',
address: 'https://your-app.com/webhooks/orders',
format: 'json'
})['data']
puts "Webhook registered: #{webhook['id']}"
Verify Webhook Signatures (Sinatra)
require 'sinatra'
require 'openssl'
require 'base64'
WEBHOOK_SECRET = ENV['TAKETHEME_WEBHOOK_SECRET']
def verify_webhook(payload, signature)
expected = Base64.strict_encode64(
OpenSSL::HMAC.digest('sha256', WEBHOOK_SECRET, payload)
)
Rack::Utils.secure_compare(expected, signature)
end
post '/webhooks/orders' do
payload = request.body.read
signature = request.env['HTTP_X_TAKETHEME_SIGNATURE']
unless verify_webhook(payload, signature)
halt 401, 'Invalid signature'
end
event = JSON.parse(payload)
puts "Order created: #{event['data']['order_number']}"
status 200
'OK'
end
Pagination Helper
def paginate(client, endpoint, params = {})
Enumerator.new do |yielder|
params = params.merge(limit: 100)
cursor = nil
loop do
params[:cursor] = cursor if cursor
params[:direction] = 'next' if cursor
response = client.get(endpoint, params)
data = response['data']
pagination = response['pagination']
data.each { |item| yielder << item }
break unless pagination['has_more']
cursor = pagination['next_cursor']
end
end
end
# Usage
paginate(client, '/products').each do |product|
puts product['title']
end
# Collect all
all_products = paginate(client, '/products').to_a
puts "Total: #{all_products.length} products"
Error Handling
class ValidationError < TakeThemeError; end
class RateLimitError < TakeThemeError
attr_reader :retry_after
def initialize(error, retry_after)
super(error)
@retry_after = retry_after
end
end
def handle_response(response)
body = JSON.parse(response.body)
case response
when Net::HTTPSuccess
body
when Net::HTTPUnprocessableEntity
raise ValidationError.new(body['error'])
when Net::HTTPTooManyRequests
retry_after = response['Retry-After']&.to_i || 60
raise RateLimitError.new(body['error'], retry_after)
else
raise TakeThemeError.new(body['error'])
end
end
# Usage
begin
client.post('/products', { title: '' }) # Invalid
rescue ValidationError => e
e.details.each do |detail|
puts "#{detail['field']}: #{detail['message']}"
end
rescue RateLimitError => e
puts "Rate limited. Retry after #{e.retry_after} seconds"
sleep(e.retry_after)
rescue TakeThemeError => e
puts "Error #{e.code}: #{e.message}"
end
Complete Example: Order Export
require 'csv'
def export_orders(client, filename, days: 30)
puts "Exporting orders from the last #{days} days..."
since = (Time.now - days * 24 * 60 * 60).iso8601
CSV.open(filename, 'w') do |csv|
csv << ['Order Number', 'Date', 'Customer', 'Total', 'Status', 'Items']
paginate(client, '/orders', created_at_min: since).each do |order|
csv << [
order['order_number'],
order['created_at'],
order.dig('customer', 'email') || 'Guest',
order['total'],
order['status'],
order['line_items']&.length || 0
]
end
end
puts "Export complete: #{filename}"
end
# Run export
client = TakeThemeClient.new(ENV['TAKETHEME_API_KEY'])
export_orders(client, 'orders.csv', days: 30)
Rails Integration
# config/initializers/taketheme.rb
Rails.application.config.taketheme = TakeThemeClient.new(
Rails.application.credentials.taketheme[:api_key]
)
# app/services/taketheme_service.rb
class TakethemeService
class << self
def client
Rails.application.config.taketheme
end
def products
@products ||= ProductsApi.new(client)
end
def orders
@orders ||= OrdersApi.new(client)
end
end
end
class ProductsApi
def initialize(client)
@client = client
end
def list(params = {})
@client.get('/products', params)['data']
end
def find(id)
@client.get("/products/#{id}")['data']
end
def create(attributes)
@client.post('/products', attributes)['data']
end
def update(id, attributes)
@client.patch("/products/#{id}", attributes)['data']
end
def destroy(id)
@client.delete("/products/#{id}")
end
end
# app/controllers/products_controller.rb
class ProductsController < ApplicationController
def index
@products = TakethemeService.products.list(limit: 25)
end
def show
@product = TakethemeService.products.find(params[:id])
end
end
Async with Sidekiq
# app/jobs/sync_products_job.rb
class SyncProductsJob
include Sidekiq::Job
def perform
client = TakeThemeClient.new(ENV['TAKETHEME_API_KEY'])
Product.find_each do |local_product|
begin
if local_product.taketheme_id.present?
client.patch("/products/#{local_product.taketheme_id}", {
title: local_product.name,
price: local_product.price,
inventory_quantity: local_product.stock
})
else
result = client.post('/products', {
title: local_product.name,
price: local_product.price,
inventory_quantity: local_product.stock
})
local_product.update!(taketheme_id: result['data']['id'])
end
rescue TakeThemeError => e
Rails.logger.error("Failed to sync product #{local_product.id}: #{e.message}")
end
end
end
end