Getting started

Exports reference

Everything envless-sdk defines under Envless: the client, the shared client, crypto helpers, constants, exceptions, result objects and the RBS types.

require "envless/sdk" loads one module, Envless. Everything below is a module function, a class or a constant on it, and the types are RBS aliases in the signatures the gem ships.

Clients

ExportSignature
Envless::Client.new(token = nil, token: nil, base_url: nil, adapter: nil, max_retries: nil, timeout: nil, user_agent: nil, disable_update_notice: false)
Envless.newThe same arguments, returning an Envless::Client
Envless.create_clientThe same, under the TypeScript name
Envless.initThe same arguments. Installs the shared client and returns it
Envless.client() -> Envless::Client, the shared client, built from the environment on first use
Envless.reset_client() -> nil
Envless.me, Envless.variables and the restEvery namespace, on the shared client

Every client reads ENVLESS_TOKEN and ENVLESS_API_ENDPOINT for the arguments you leave out. See Create a client.

ruby
require "envless/sdk"

Envless.init(timeout: 10)

Envless.products.list

Crypto

ExportSignature
Envless.encrypt_value(String plaintext, String passphrase, String workspace_unique_id) -> String
Envless.decrypt_value(String ciphertext, String passphrase, String workspace_unique_id) -> String
Envless.encrypt_with_key(WorkspaceKey | String key, String plaintext) -> String
Envless.decrypt_with_key(WorkspaceKey | String key, String ciphertext) -> String
Envless.derive_workspace_key(String passphrase, String workspace_unique_id) -> WorkspaceKey
Envless.import_workspace_key(String key) -> WorkspaceKey
Envless.ciphertext?(untyped value) -> bool
Envless.passphrase_strength(untyped passphrase) -> Validation
Envless::WorkspaceKeyA derived or imported AES-256 key that prints as #<Envless::WorkspaceKey [redacted]>
Envless::ENCRYPTION_PARAMETERSThe exact cryptographic constants, as a frozen Hash

They are plain synchronous calls: encryption is CPU work. See Encryption for the recipe and for why you should derive the key once when writing a batch.

Helpers

ExportSignature
Envless.rotate_workspace_passphrase(client:, workspace_unique_id:, from:, to:, project:, environment:, product: nil) -> RotationResult
Envless.verify_webhook_signature(payload:, headers:, secret:, tolerance_seconds: nil) -> webhook_event[Hash[Symbol, untyped]]
Envless.variable_name_validation(untyped name) -> Validation

rotate_workspace_passphrase re-encrypts live variables and version history for one environment, which is the part that is easy to forget. verify_webhook_signature is the receiver side of Webhooks. variable_name_validation returns an Envless::Validation without raising, for checking a name in your own form or importer against the rule every write applies before it sends anything.

ruby
require "envless/sdk"

check = Envless.variable_name_validation("1_PASSWORD")

puts check.error unless check.valid?

Exceptions

ExportNotes
Envless::ErrorThe base of every exception below, a StandardError.
Envless::ApiErrorThe API answered with a failure. Carries status, code, message, resource, field, request_id, retry_after_seconds.
Envless::NetworkErrorNothing came back: connection failure or timeout. Carries message, timeout? and the cause.
Envless::DecryptionErrorA value does not decrypt.
Envless::WebhookVerificationErrorA delivery fails verification.

A mistake in the call itself raises Ruby's own ArgumentError. See Errors.

Results

ExportMembers
Envless::Pageitems, pagination, has_more?, total_count
Envless::ProductAccessPageThe same, plus is_private and private?
Envless::Validationvalid, valid?, error
Envless::RotationResultvariables, version_entries, skipped, failures
Envless::RotationIssuescope, id, field, reason
Envless::HttpRequestmethod, url, headers, body, timeout, what an adapter receives
Envless::HttpResponsestatus, headers, body, reason, what an adapter may return

They are Data values, so they are immutable, compare by value and work with pattern matching. Everything else the SDK returns is a plain Hash with Symbol keys.

Constants

Enum-like values, so you never hard-code a string the API might reject. Each is a frozen Hash with Symbol keys, such as Envless::SCOPE_LEVELS[:READ].

ExportKeys
Envless::SCOPE_RESOURCESWORKSPACE, PRODUCTS, PRODUCT_ACCESS, PROJECTS, ENVIRONMENTS, VARIABLES, VERSIONS, MEMBERS, ROLES, KEYS, WEBHOOKS
Envless::SCOPE_LEVELSNONE, READ, WRITE
Envless::VARIABLE_TYPESTRING, NUMBER, BOOLEAN
Envless::VARIABLE_VISIBILITY_LEVELSSERVER, CLIENT
Envless::WEBHOOK_SIGNATURE_HEADERSID, TIMESTAMP, SIGNATURE, EVENT, DELIVERY
Envless::PAGE_LIMITSMAX_LIMIT is 100, DEFAULT_LIMIT is 25
Envless::VERSIONThe gem version, a String
ruby
require "envless/sdk"

resources = Envless::SCOPE_RESOURCES
read = Envless::SCOPE_LEVELS[:READ]

Envless.keys.create(
  name: "ci",
  scopes: {
    resources[:VARIABLES] => read,
    resources[:VERSIONS] => read
  }
)

passphrase = ENV.fetch("ENVLESS_PASSPHRASE")
workspace_id = Envless.me.get[:workspaceId]
url = Envless.encrypt_value("https://api.acme.com", passphrase,
  workspace_id)

Envless.variables.create("web", "production",
  name: "NEXT_PUBLIC_API_URL",
  value: url,
  visibility: Envless::VARIABLE_VISIBILITY_LEVELS[:CLIENT])

Types

The gem ships RBS signatures in sig/, and every request body and every response has a type alias under Envless, named after its TypeScript twin in snake_case: VariableResource is Envless::variable_resource. They describe plain Hashes, so they cost nothing at runtime. Point Steep at the installed gem's signatures and it checks every key you send and read.

Steepfile
target :app do
  check "app"
  signature "sig"
  library "envless-sdk"
end

Pages and pagination

Envless::Page[T], Envless::ProductAccessPage, pagination_envelope

Resources

identity_resource, user_summary, role_summary, actor_reference, actor_key_reference, workspace_resource, current_workspace_resource, updated_workspace_resource, deleted_workspace_resource, custom_domain_resource, custom_domain_record, removed_domain_resource, product_resource, deleted_product_resource, product_access_entry, granted_product_access_resource, revoked_product_access_resource, project_resource, deleted_project_resource, environment_resource, environment_summary_resource, deleted_environment_resource, variable_resource, deleted_variable_resource, deleted_variables_resource, created_variables_resource, variable_history_event, version_resource, version_detail_resource, version_entry_resource, rolled_back_version_resource, reencrypted_entries_resource, member_resource, deleted_member_resource, left_workspace_resource, invite_resource, revoked_invite_resource, role_resource, deleted_role_resource, permission_resource, permissions_resource, key_resource, created_key_resource, deleted_key_resource, webhook_resource, created_webhook_resource, deleted_webhook_resource, rotated_secret_resource, webhook_delivery_resource, webhook_delivery_detail_resource, redelivered_webhook_resource, event_types_resource

Inputs

workspace_create, workspace_patch, product_create, product_patch, project_create, project_patch, environment_create, environment_patch, variable_input, variable_patch, version_create, member_invite, member_patch, role_create, role_patch, key_create, key_patch, webhook_create, webhook_patch, apply_changes, apply_baseline_entry, apply_update_entry, apply_result, reencrypt_entry_input

Crypto and webhooks

encryption_parameters, webhook_event[T], plus the Envless::Validation, Envless::RotationResult and Envless::RotationIssue classes

A method that takes a body accepts the record type or any Hash[Symbol | String, untyped], so a Hash you build at runtime still type-checks, while a literal is checked key by key. Options are keywords rather than types, so there is no ListOptions or RequestScope in Ruby.

Read shapes are not always the write shapes. environments.get returns environment_summary_resource, while environments.update returns the full environment_resource. The method pages call these out individually.

A worked example

ruby
require "envless/sdk"

passphrase = ENV.fetch("ENVLESS_PASSPHRASE")
workspace_id = Envless.me.get[:workspaceId]
key = Envless.derive_workspace_key(passphrase, workspace_id)

product = Envless.products.create(name: "Internal tools",
  slug: "internal-tools")
slug = product[:slug]
project = Envless.projects.create(name: "API", slug: "api",
  product: slug)

%w[development staging production].each do |name|
  Envless.environments.create(project[:slug], name:, slug: name,
    product: slug)
end

database_url = ENV.fetch("DATABASE_URL")

Envless.variables.create_many("api", "production", [
  {name: "DATABASE_URL",
   value: Envless.encrypt_with_key(key, database_url)},
  {name: "PORT", value: Envless.encrypt_with_key(key, "3000"),
   type: "number"}
], product: slug)

Envless.versions.create("api", "production",
  note: "Initial provisioning", product: slug)

runner = Envless.keys.create(
  name: "api-runner",
  scopes: {variables: Envless::SCOPE_LEVELS[:READ]},
  projectIds: [project[:id]]
)

puts runner[:secret]