humantone

Official Ruby SDK for the HumanTone API. Rewrites AI-generated text into natural-sounding prose. Adds an AI Likelihood Indicator that scores how AI-like any text reads.

Gem Version CI License: MIT

Install

Add to your Gemfile:

gem "humantone", "~> 0.0.1"

Then bundle install.

Or directly: gem install humantone.

Requires Ruby 3.3 or later. Zero runtime dependencies (uses stdlib net/http).

Quickstart

require "humantone"

client = HumanTone::Client.new(api_key: ENV.fetch("HUMANTONE_API_KEY"))

result = client.humanize(
  text: "Your AI-generated draft goes here. At least 30 words for the API to accept it."
)

puts result.text
puts "Credits used: #{result.credits_used}"

The client also picks up HUMANTONE_API_KEY from the environment automatically:

client = HumanTone::Client.new

API

client.humanize(text:, level:, output_format:, custom_instructions:)

Argument Type Default Notes
text: String required Min 30 words. Max depends on plan (Basic 750, Standard 1000, Pro 1500).
level: `:standard \ :advanced \ :extreme`
output_format: `:text \ :html \ :markdown`
custom_instructions: String or nil nil Free-form rewrite guidance. Max 1000 chars.

Returns HumanTone::HumanizeResult Data with #text, #output_format, #credits_used, #request_id.

client.detect(text:)

Returns DetectResult with #ai_score (0-100 integer). Free, but limited to 30 calls per day per account.

client.account.get

info = client..get
puts info.plan.name
puts info.credits.total
puts info.subscription.expires_at  # Time or nil

Configuration

client = HumanTone::Client.new(
  api_key: "ht_...",                    # or HUMANTONE_API_KEY env
  base_url: "https://api.humantone.io", # or HUMANTONE_BASE_URL env, default
  timeout: 120,                          # seconds
  max_retries: 2,
  retry_on_post: false,                  # POST endpoints retry only when explicit
  user_agent: "my-app/1.0"               # appended to default UA after a single space
)

Error handling

All errors inherit from HumanTone::Error.

begin
  result = client.humanize(text: "...")
rescue HumanTone::InsufficientCreditsError
  puts "Buy more credits at https://app.humantone.io/settings/credits"
rescue HumanTone::RateLimitError => e
  puts "Rate limited. Retry in #{e.retry_after_seconds}s."
rescue HumanTone::AuthenticationError
  puts "Check your API key."
rescue HumanTone::Error => e
  puts "HumanTone error (#{e.error_code}): #{e.message}"
  puts "Request ID: #{e.request_id}" if e.request_id
end

Error classes:

  • AuthenticationError, PermissionError, RateLimitError
  • InsufficientCreditsError, DailyLimitExceededError
  • InvalidRequestError, NotFoundError
  • APIError, TimeoutError, NetworkError

Common methods on every error:

  • #message, #status_code, #request_id, #error_code, #details, #retryable?

Specific accessors: RateLimitError#retry_after_seconds: Integer, DailyLimitExceededError#time_to_next_renew: Integer | nil, InsufficientCreditsError#required_credits and #available_credits.

Retry behavior

The SDK retries account.get on network errors, 5xx, and 429 (up to 2 retries). POST methods (humanize, detect) do not retry on network or 5xx by default. Humanize debits credits, so a retried request risks double-billing. Pass retry_on_post: true to opt in. 429 always retries on every method.

Retry-After headers are honored in both numeric (seconds) and HTTP-date formats.

Limits to remember

  • Per-request word limit. Basic 750, Standard 1000, Pro 1500. Inputs must be at least 30 words.
  • Credits. Humanize consumes 1 credit per 100 words. Account checks and AI likelihood checks do not consume credits.
  • AI likelihood quota. 30 checks per day per account, shared between the HumanTone web app and any API or SDK usage. Resets at midnight UTC.
  • API access. Included on all paid plans. Free trial accounts cannot use the API.

Get an API key

Sign up at humantone.io. The HumanTone API is paid only.

License

MIT