Canonical page: https://docs.singlebase.io/sdk-ruby

# Ruby SDK

A small client you can copy into your backend. This is a documented implementation, not a separately published package. It sends the same API envelope for every service through one `call` method.

Ruby 2.5+; standard library only.

## Response contract

| Field | Meaning |
|---|---|
| `data` | Operation result; absent on API errors |
| `error` | API error object, or null/nil on success; `message` is the stable code |
| `meta` | Response metadata, including pagination when returned |
| `exec_time` | Gateway execution time in seconds, when returned |

API errors return in `Result.error`. Network, invalid JSON, and transport failures raise an exception or return a Go error. These small clients do not manage sessions, auto-refresh tokens, or retry requests. Pass a current user bearer token to the constructor/client only when acting as that user; omit it for trusted server/agent calls. Keep keys on the server.

## Client implementation

Save as `singlebase.rb`. [Download the source](/examples/singlebase.rb).

```ruby
require 'json'
require 'net/http'
require 'uri'

Result = Struct.new(:data, :error, :meta, :exec_time, keyword_init: true)

class SinglebaseClient
  def initialize(api_key:, api_url:, bearer: nil)
    @api_key, @api_url, @bearer = api_key, api_url, bearer
  end

  def call(operation:, payload:, options: nil)
    uri = URI(@api_url)
    request = Net::HTTP::Post.new(uri)
    request['Content-Type'] = 'application/json'
    request['X-API-KEY'] = @api_key
    request['Authorization'] = "Bearer #{@bearer}" if @bearer
    body = {operation: operation, payload: payload}
    body[:options] = options unless options.nil?
    request.body = JSON.generate(body)
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = uri.scheme == 'https'
    http.open_timeout = 30
    http.read_timeout = 30
    response = http.request(request)
    decoded = JSON.parse(response.body)
    unless decoded.is_a?(Hash)
      raise 'Expected a JSON API envelope'
    end
    if response.code.to_i >= 400 && !decoded['error']
      raise "HTTP #{response.code} without an API error envelope"
    end
    Result.new(data: decoded['data'], error: decoded['error'], meta: decoded['meta'] || {}, exec_time: decoded['exec_time'])
  end
end
```

## Example

Set `SINGLEBASE_API_URL` to the complete console endpoint and `SINGLEBASE_API_KEY` to your server or appropriately scoped agent key. The `notes` collection must exist.

```ruby
require_relative 'singlebase'
sbc = SinglebaseClient.new(api_key: ENV.fetch('SINGLEBASE_API_KEY'), api_url: ENV.fetch('SINGLEBASE_API_URL'))
resp = sbc.call(operation: 'data.query', payload: {collection: 'notes', limit: 5}, options: {})
raise resp.error['message'] if resp.error
puts resp.data.inspect
puts resp.meta.inspect
puts resp.exec_time
```

Use the same method with `llm.summarize` for generation or `chat.ask` for an answer, with the operation's verified payload. The `options` argument goes in the request envelope, separate from `payload`. An empty options object is valid; omit it when unused. See [API overview](/api.md) for request access and errors, and [API reference](/api-reference.md) for the operation groups.
