Skip to main content

Ruby SDK

The official Pictify SDK for Ruby provides an idiomatic Ruby interface for the Pictify API.

Installation

Add to your Gemfile:
gem 'pictify'
Then run:
bundle install
Or install directly:
gem install pictify

Quick Start

require 'pictify'

client = Pictify::Client.new('pk_live_your_api_key')

image = client.images.create(
  html: '<h1 style="color: #667eea;">Hello World</h1>',
  width: 1200,
  height: 630
)

puts image['url']

Configuration

Basic Configuration

client = Pictify::Client.new('pk_live_your_api_key')

Advanced Configuration

client = Pictify::Client.new(
  'pk_live_your_api_key',
  base_url: 'https://api.pictify.io/v1',
  timeout: 30,
  max_retries: 3
)

Environment Variables

# Reads PICTIFY_API_KEY from environment
client = Pictify::Client.new(ENV['PICTIFY_API_KEY'])

Rails Configuration

# config/initializers/pictify.rb
Pictify.configure do |config|
  config.api_key = Rails.application.credentials.pictify_api_key
  config.timeout = 30
end
Then use the global client:
image = Pictify.images.create(html: '...', width: 1200, height: 630)

Images

Generate from HTML

image = client.images.create(
  html: <<~HTML,
    <div style="width: 1200px; height: 630px; background: #667eea;
                display: flex; align-items: center; justify-content: center;">
      <h1 style="color: white; font-size: 48px;">Hello World</h1>
    </div>
  HTML
  width: 1200,
  height: 630,
  format: 'png'
)

puts image['url']    # https://cdn.pictify.io/renders/...
puts image['id']     # img_abc123
puts image['width']  # 1200
puts image['height'] # 630

Generate from URL

screenshot = client.images.create(
  url: 'https://example.com',
  width: 1200,
  height: 630,
  full_page: false
)

Canvas Rendering

image = client.images.canvas(
  fabric_js_data: {
    version: '5.3.0',
    objects: [
      { type: 'rect', fill: '#667eea', width: 1200, height: 630 },
      { type: 'textbox', text: '{{title}}', fill: 'white', fontSize: 48 }
    ]
  },
  variables: { title: 'Dynamic Content' },
  width: 1200,
  height: 630
)

Agent Screenshot

screenshot = client.images.agent_screenshot(
  prompt: 'Take a screenshot of the pricing section on stripe.com'
)

GIFs

Create from HTML

gif = client.gifs.create(
  html: <<~HTML,
    <div class="container">
      <style>
        @keyframes pulse {
          0% { transform: scale(1); }
          50% { transform: scale(1.1); }
          100% { transform: scale(1); }
        }
        .pulse { animation: pulse 1s infinite; }
      </style>
      <div class="pulse">Animated!</div>
    </div>
  HTML
  width: 400,
  height: 400
)

Capture from URL

gif = client.gifs.capture(
  url: 'https://example.com/animated',
  width: 800,
  height: 600,
  quality: 'high',
  frame_duration_seconds: 5
)

PDFs

Single Page

pdf = client.pdfs.render(
  template_uid: 'tmpl_invoice',
  variables: {
    invoiceNumber: 'INV-001',
    items: [{ name: 'Service', price: 99.00 }],
    total: 99.00
  },
  options: {
    preset: 'A4',
    margins: { top: 40, bottom: 40, left: 30, right: 30 }
  }
)

Multi-Page

pdf = client.pdfs.multi_page(
  template_uid: 'tmpl_report',
  variable_sets: [
    { pageTitle: 'Introduction', content: '...' },
    { pageTitle: 'Analysis', content: '...' },
    { pageTitle: 'Conclusion', content: '...' }
  ],
  options: { preset: 'A4' }
)

Templates

List Templates

result = client.templates.list(page: 1, limit: 20)
templates = result['templates']
pagination = result['pagination']

Create Template

template = client.templates.create(
  name: 'Social Card',
  html: '<h1>{{title}}</h1><p>{{description}}</p>',
  width: 1200,
  height: 630
)

Render Template

image = client.templates.render(
  'tmpl_abc123',
  variables: {
    title: 'My Post',
    description: 'An interesting article'
  },
  format: 'png'
)

Get Variables

result = client.templates.get_variables('tmpl_abc123')
variables = result['variables']
# [{ 'name' => 'title', 'type' => 'string', 'required' => true }, ...]

Batch Render

batch = client.templates.batch_render(
  'tmpl_abc123',
  variable_sets: [
    { title: 'Post 1' },
    { title: 'Post 2' },
    { title: 'Post 3' }
  ],
  webhook_url: 'https://your-server.com/webhooks/batch'
)

# Later, get results
results = client.templates.get_batch_results(batch['id'])

Webhooks

Create Subscription

subscription = client.webhooks.create(
  event: 'render.completed',
  target_url: 'https://your-server.com/webhooks/pictify'
)

# Store this secret securely!
puts subscription['secret']

Verify Signature

require 'openssl'

def verify_webhook_signature(payload, signature_header, secret)
  parts = signature_header.split(',').map { |p| p.split('=') }.to_h
  timestamp = parts['t'].to_i
  provided_signature = parts['v1']

  # Reject if timestamp is older than 5 minutes
  if (Time.now.to_i - timestamp).abs > 300
    raise 'Webhook timestamp too old'
  end

  signed_payload = "#{timestamp}.#{payload}"
  expected_signature = OpenSSL::HMAC.hexdigest('SHA256', secret, signed_payload)

  Rack::Utils.secure_compare(provided_signature, expected_signature)
end

Rails Controller

# app/controllers/webhooks_controller.rb
class WebhooksController < ApplicationController
  skip_before_action :verify_authenticity_token

  def pictify
    signature = request.headers['X-Pictify-Signature']
    payload = request.raw_post

    begin
      unless verify_webhook_signature(payload, signature, ENV['PICTIFY_WEBHOOK_SECRET'])
        return head :unauthorized
      end

      event = JSON.parse(payload)
      Rails.logger.info "Received Pictify event: #{event['event']}"

      # Handle the event
      case event['event']
      when 'render.completed'
        handle_render_completed(event['data'])
      when 'render.failed'
        handle_render_failed(event['data'])
      end

      head :ok
    rescue => e
      Rails.logger.error "Webhook error: #{e.message}"
      head :bad_request
    end
  end

  private

  def verify_webhook_signature(payload, signature_header, secret)
    # ... signature verification code
  end

  def handle_render_completed(data)
    # Update your records, notify users, etc.
  end

  def handle_render_failed(data)
    # Log error, retry, notify, etc.
  end
end

Sinatra Example

require 'sinatra'
require 'json'

post '/webhooks/pictify' do
  signature = request.env['HTTP_X_PICTIFY_SIGNATURE']
  payload = request.body.read

  begin
    unless verify_webhook_signature(payload, signature, ENV['WEBHOOK_SECRET'])
      halt 401, 'Invalid signature'
    end

    event = JSON.parse(payload)
    puts "Received event: #{event['event']}"

    status 200
    'OK'
  rescue => e
    halt 400, e.message
  end
end

Bindings

Create Binding

binding = client.bindings.create(
  name: 'GitHub Stats',
  template_uid: 'tmpl_github',
  data_url: 'https://api.github.com/repos/your/repo',
  data_mapping: {
    stars: 'stargazers_count',
    forks: 'forks_count'
  },
  schedule: '0 * * * *'  # Hourly
)

# Permanent image URL that auto-updates
puts binding['imageUrl']

Trigger Refresh

client.bindings.refresh('bind_abc123')

Error Handling

begin
  image = client.images.create(...)
rescue Pictify::RateLimitError => e
  # Wait and retry
  puts "Rate limited. Retry after #{e.retry_after}s"
  sleep(e.retry_after)
  retry
rescue Pictify::ValidationError => e
  # Fix validation issues
  puts "Validation errors: #{e.errors}"
rescue Pictify::AuthenticationError
  # Check API key
  puts "Invalid API key"
rescue Pictify::APIError => e
  # General API error
  puts "API Error: #{e.message} (status: #{e.status})"
end

Rails Integration

Model Concern

# app/models/concerns/pictify_renderable.rb
module PictifyRenderable
  extend ActiveSupport::Concern

  included do
    after_commit :generate_og_image, on: [:create, :update], if: :should_regenerate_og_image?
  end

  def og_image_url
    return unless og_image_id
    "https://cdn.pictify.io/renders/#{og_image_id}.png"
  end

  private

  def should_regenerate_og_image?
    saved_change_to_title? || saved_change_to_description?
  end

  def generate_og_image
    GenerateOgImageJob.perform_later(self.class.name, id)
  end
end

Background Job

# app/jobs/generate_og_image_job.rb
class GenerateOgImageJob < ApplicationJob
  queue_as :default

  def perform(model_class, model_id)
    record = model_class.constantize.find(model_id)

    image = Pictify.templates.render(
      'tmpl_og',
      variables: {
        title: record.title,
        description: record.description,
        author: record.author&.name
      }
    )

    record.update!(og_image_id: image['id'])
  end
end

View Helper

# app/helpers/pictify_helper.rb
module PictifyHelper
  def pictify_og_image(record)
    return unless record.respond_to?(:og_image_url) && record.og_image_url
    tag.meta property: 'og:image', content: record.og_image_url
  end
end

API Reference

See the API Reference for full endpoint documentation.