OnetimeSecret Ruby Client
The official Ruby client for the OnetimeSecret API. Share sensitive information through a link that can only be viewed once.
-
Zero runtime dependencies — built entirely on the Ruby standard library
(
net/http,uri,json), so it drops into any environment without pulling transitive gems. - Supports API v1 and v2 — pick a version per client. The same resource methods exist for both, but each version returns its own response shape (they are different APIs; the client does not normalize them). v1 is deprecated and included only because the service still serves it — use v2 for new work.
- Ruby 3.1+.
The
onetimecommand-line tool has moved to a separateonetime-cligem so that this library stays dependency-free.
Installation
gem install onetimeOr in a Gemfile:
gem "onetime"Quick start
require "onetime"
client = Onetime::Client.new(
base_url: "https://us.onetimesecret.com", # your region's API host (required)
organization: "on1abc...", # organization extid (see below)
api_token: ENV["ONETIME_API_TOKEN"], # API token from your account page
api_version: :v2, # :v1 or :v2 (default :v2)
)
# Conceal a secret you already have
res = client.secrets.conceal(secret: "hunter2", ttl: 3600, passphrase: "pw")
res.dig("record", "receipt", "identifier") # the receipt (creator) key
res.dig("record", "secret", "identifier") # the secret (recipient) key
# Generate a random secret server-side
client.secrets.generate(ttl: 86_400)
# Reveal (consume) a secret — one-time only
secret = client.secrets.reveal("abc123secretkey", passphrase: "pw")
secret.dig("record", "secret_value")
# Service status (works on v1 and v2)
client.statusAuthentication
Authentication uses HTTP Basic, where the organization extid is the username and your API token is the password.
The organization extid is the identifier beginning with on shown (with a
copy button) at the bottom of the user menu when you are signed in. It is no
longer your email address.
Base URL (required)
base_url must be the API host for your region, your self-hosted domain, or
your custom domain. There is no default: deployments are region-isolated for
data sovereignty, so the client cannot guess one for you.
Regional API hosts:
| Region | Host |
|---|---|
| United States | https://us.onetimesecret.com |
| Europe | https://eu.onetimesecret.com |
| United Kingdom | https://uk.onetimesecret.com |
| Canada | https://ca.onetimesecret.com |
| Aotearoa New Zealand | https://nz.onetimesecret.com |
The apex
onetimesecret.comis the company website, not an API host, and is rejected with a helpful error.
Configuration
| Option | Default | Notes |
|---|---|---|
base_url |
— (required) | Region/self-hosted/custom domain |
api_version |
:v2 |
:v1 or :v2
|
organization |
ENV["ONETIME_ORG_EXTID"] |
Organization extid (on...) |
api_token |
ENV["ONETIME_API_TOKEN"] |
API token |
timeout |
30 |
Read timeout (seconds) |
open_timeout |
10 |
Connect timeout (seconds) |
max_retries |
2 |
Retries for idempotent (GET) requests |
Environment fallbacks: base_url ← ONETIME_BASE_URL; organization ←
ONETIME_ORG_EXTID; api_token ← ONETIME_API_TOKEN.
Clients are thread-safe: they hold only configuration and a stateless transport, opening a fresh connection per request.
Anonymous and guest usage
A client created without credentials is anonymous and can use public and guest endpoints:
guest = Onetime::Client.new(base_url: "https://us.onetimesecret.com") # no credentials
guest.secrets.conceal(secret: "no account needed", guest: true)Resources
client.secrets
| Method | v1 | v2 |
|---|---|---|
conceal(secret:, ttl:, passphrase:, recipient:, share_domain:) |
yes | yes |
generate(ttl:, passphrase:, recipient:, share_domain:) |
yes | yes |
reveal(key, passphrase:, continue:) |
yes | yes |
show(key) |
— | yes |
status(key) |
— | yes |
status_list(keys) |
— | yes |
conceal is also available as share. reveal/show accept either a bare
key or a full secret URL.
client.receipts
| Method | v1 | v2 |
|---|---|---|
show(key) |
yes | yes |
recent |
yes | yes |
burn(key, passphrase:, continue:) |
yes | yes |
update(key, memo:) |
— | yes |
Meta
client.status (v1 & v2), client.version / client.supported_locales
(v2 only), client.authcheck (v1 only).
Responses
Resource methods return an Onetime::Response with indifferent (String or
Symbol) key access:
res = client.secrets.conceal(secret: "hi")
res["record"] # Hash
res.dig(:record, :secret, :secret_value) # deep access
res.success? # 2xx?
res.http_status # Integer
res.to_h # the parsed bodyThe response shape is the API's, unchanged. v1 and v2 differ on purpose —
v1 returns flat, all-string fields; v2 nests data under record/details
with richer typing — and the client does not reconcile them. Read the
API docs for the shape of the version
you target.
Errors
HTTP errors (status >= 400) raise typed exceptions following the API's
ADR-013 error contract ({ error:, error_type:, ... }):
begin
client.secrets.reveal("missing")
rescue Onetime::NotFoundError => e
e.message # human-readable message ("error" field)
e.error_type # machine-readable type ("RecordNotFound")
e.http_status # 404
rescue Onetime::RateLimitError => e
e.retry_after
rescue Onetime::APIError => e
# any other API error
end| Exception | When |
|---|---|
Onetime::BadRequestError |
400 / FormError (see #field) |
Onetime::AuthenticationError |
401 |
Onetime::ForbiddenError |
403 / Forbidden, GuestRoutesDisabled
|
Onetime::EntitlementError |
EntitlementRequired (see #entitlement) |
Onetime::NotFoundError |
404 / RecordNotFound
|
Onetime::RateLimitError |
429 / LimitExceeded (see #retry_after) |
Onetime::ServerError |
5xx |
Onetime::TransportError / TimeoutError
|
network failures |
All inherit from Onetime::Error.
Development
bundle install
rake testLicense
See LICENSE.txt.