Working Ruby code for the Claude API using net/http. No official Ruby gem needed — call Claude from Rails, Sinatra, or plain Ruby scripts with these copy-paste examples.
Anthropic has no official Ruby gem as of 2026, so the idiomatic approach is to call the REST API directly via Ruby's built-in net/http. These examples work in plain Ruby scripts, Rails, and Sinatra.
require 'net/http'
require 'json'
require 'uri'
def claude(prompt, model: "claude-sonnet-4-6", max_tokens: 1024)
uri = URI("https://api.anthropic.com/v1/messages")
req = Net::HTTP::Post.new(uri, {
"x-api-key" => ENV["ANTHROPIC_API_KEY"],
"anthropic-version" => "2023-06-01",
"content-type" => "application/json"
})
req.body = JSON.generate({
model: model,
max_tokens: max_tokens,
messages: [{ role: "user", content: prompt }]
})
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
JSON.parse(res.body).dig("content", 0, "text")
end
puts claude("Explain Ruby blocks in one paragraph.")
req.body = JSON.generate({
model: "claude-sonnet-4-6",
max_tokens: 512,
system: "You are a concise Ruby expert. Answer in bullet points.",
messages: [{ role: "user", content: "What is the difference between Proc and Lambda?" }]
})
require 'net/http'
require 'json'
require 'uri'
class ClaudeClient
BASE_URI = URI("https://api.anthropic.com/v1/messages").freeze
def initialize(api_key: ENV["ANTHROPIC_API_KEY"], model: "claude-sonnet-4-6")
@api_key = api_key
@model = model
end
def chat(messages, system: nil, max_tokens: 1024)
body = { model: @model, max_tokens: max_tokens, messages: messages }
body[:system] = system if system
req = Net::HTTP::Post.new(BASE_URI, headers)
req.body = JSON.generate(body)
res = Net::HTTP.start(BASE_URI.hostname, BASE_URI.port, use_ssl: true) { |h| h.request(req) }
raise "Claude error #{res.code}: #{res.body}" unless res.is_a?(Net::HTTPSuccess)
JSON.parse(res.body).dig("content", 0, "text")
end
private
def headers
{
"x-api-key" => @api_key,
"anthropic-version" => "2023-06-01",
"content-type" => "application/json"
}
end
end
client = ClaudeClient.new
puts client.chat([{ role: "user", content: "Write a Ruby one-liner that reverses each word in a string." }])
require 'net/http'
require 'json'
require 'uri'
uri = URI("https://api.anthropic.com/v1/messages")
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
req = Net::HTTP::Post.new(uri, {
"x-api-key" => ENV["ANTHROPIC_API_KEY"],
"anthropic-version" => "2023-06-01",
"content-type" => "application/json"
})
req.body = JSON.generate({
model: "claude-sonnet-4-6",
max_tokens: 1024,
stream: true,
messages: [{ role: "user", content: "Explain metaprogramming in Ruby." }]
})
http.request(req) do |res|
buffer = ""
res.read_body do |chunk|
buffer += chunk
while (line = buffer.slice!(/^data: .+
/))
data = line.sub("data: ", "").strip
next if data == "[DONE]"
event = JSON.parse(data) rescue next
if event.dig("delta", "type") == "text_delta"
print event.dig("delta", "text")
$stdout.flush
end
end
end
end
end
puts
def claude_with_retry(prompt, retries: 3)
delay = 1
retries.times do |attempt|
result = claude(prompt)
return result
rescue => e
raise e if attempt == retries - 1
sleep delay
delay *= 2
end
end
# config/initializers/claude.rb
require_relative "../../lib/claude_client"
CLAUDE = ClaudeClient.new(api_key: Rails.application.credentials.anthropic_api_key)
# app/controllers/chat_controller.rb
class ChatController < ApplicationController
def create
reply = CLAUDE.chat([{ role: "user", content: params[:message] }])
render json: { reply: reply }
end
end
| Aspect | Ruby (net/http) | Python (anthropic SDK) |
|---|---|---|
| Official package | None — use net/http | pip install anthropic |
| Streaming | Manual SSE parsing | client.messages.stream() context manager |
| Retry / backoff | Manual | Built-in via SDK |
| Rails integration | Service object or initializer | N/A |
| Async | Ractors / async-http gem | AsyncAnthropic class |
To estimate token costs for your Ruby app, use the Claude API Cost Calculator. For pricing details, see the Anthropic API pricing page.