Variables

Envless.variables.create_many

Create up to 200 variables in one call

def create_many(project, environment, items, product: nil, timeout: nil)

Creates up to 200 variables in a single request. This route is partial success by design: an item the server refuses is reported in skipped and the rest are still created, so read skipped and count instead of reading a successful call as full success. A batch in which every single item is refused does not return a 201, it raises Envless::ApiError with the 4xx status and the per-item reasons.

An item is skipped rather than fatal when its name repeats inside the request, its value, type, visibility or default fails validation, it collides with an existing live variable, or it would push the environment past the 1000 variable cap. Items are processed in request order, so an overflow drops the tail rather than an arbitrary subset.

Every name is held to the same rule as create: ^[A-Za-z_][A-Za-z0-9_]*$, 1 to 100 characters, stored with exactly the casing you send. Names are compared without regard to case throughout, so two items in one batch that differ only in case collide with each other, and api_key collides with a live API_KEY. The SDK checks every name against that rule before sending, so a name that fails the shape or the length bound refuses the whole batch locally instead of coming back in skipped.

Ciphertext is checked per item, exactly as create does. A plaintext value or defaultValue anywhere in the batch aborts the whole request with 400 variable.ciphertext_invalid, naming the offending variable, and nothing is written. Encrypt every value before you send it.

Example

ruby
require "envless/sdk"

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

plaintext = {
  "SENTRY_DSN" => "https://key@o1.ingest.sentry.io/1",
  "REDIS_URL" => "redis://cache.internal:6379"
}
items = plaintext.map do |name, value|
  {name:, value: Envless.encrypt_with_key(key, value)}
end

result = Envless.variables.create_many("api", "production", items)

puts result[:count]
puts result[:skipped] unless result[:skipped].empty?

Parameters

ParameterTypeRequiredDescription
projectStringYesProject slug the environment belongs to.
environmentStringYesEnvironment slug to create the variables in.
itemsArray[variable_input]YesBetween 1 and 200 variables, each with a name matching ^[A-Za-z_][A-Za-z0-9_]*$ of 1 to 100 characters and a ciphertext value.
product:String | SymbolNoProduct slug, needed when the project slug is not unique in the workspace.
timeout:Integer | Float | RationalNoSeconds each attempt of this call may take, redirects and the response body included, before it raises Envless::NetworkError with timeout? set. Overrides the client's timeout for this call, and 0 turns the limit off.

Returns

created_variables_resource with created, skipped carrying a reason per name, and count of rows actually written.

Worth knowing

  • A call that returns always created at least one variable. Everything the server refused is in skipped, so inspect it on every call.
  • A batch where nothing was accepted raises rather than returning, so an error here can mean bad names as easily as a transport failure. Read the per-item reasons before retrying.
  • Names are case reserved, not case normalised. Sending API_KEY and api_key in the same batch creates one of them and skips the other.
  • Every name is checked locally before anything is sent, so one unusable name fails the whole batch with an Envless::ApiError carrying request.body_invalid instead of arriving as a skipped entry.

Required scopes

variables:write

Underlying endpoint

POST /projects/{slug}/environments/{environmentSlug}/variables/bulk

Request and response schema, every error code, and a live playground.

In TypeScript

envless.variables.createMany()

The same method in @goenvless/sdk, with the same request, retries and errors.