Reference

SDK Cheat Sheet

One-page reference for common Onyx SDK calls. Select a language to see the syntax.

Onyx Environment Variables

Set these to control how the SDK scopes requests and where it fetches credentials.

Kotlin
Env VarDescriptionDefault
ONYX_DATABASE_IDDatabase UUID used to scope requests; required.none
ONYX_DATABASE_BASE_URLHTTP base for DB API.https://api.onyx.dev
ONYX_DATABASE_API_KEYAPI key for the database; required.none
ONYX_DATABASE_API_SECRETAPI secret for the database; required.none
ONYX_AI_BASE_URLBase URL for AI/chat endpoints.https://ai.onyx.dev
ONYX_DEFAULT_MODELModel used by db.chat() shorthand.onyx
ONYX_CONFIG_PATHPath to JSON credentials file; checked after env vars.unset
ONYX_DEBUGWhen 'true', enables request/response logging and config debug output.false
ONYX_STREAM_DEBUGWhen 'true'/'1', logs streaming connection details.false

Initialization Patterns

Initialize the SDK with configuration.

Kotlin

Auto resolution

Resolution order: env vars → ONYX_CONFIG_PATH file → ./onyx-database.json (default locations).

import com.onyx.cloud.api.onyx

val db = onyx.init<Any>()

Initialize with config object

Pass credentials directly when you can’t rely on env/file resolution.

import com.onyx.cloud.api.onyx

val db = onyx.init<Any>(
    OnyxConfig(
        apiKey = ONYX_DATABASE_API_KEY,
        apiSecret = ONYX_DATABASE_API_SECRET,
    )
)

Optional config fields

AttributeDescriptionDefault
baseUrlREST base URL for database operations.https://api.onyx.dev
databaseIdDatabase ID (inferred for DB-scoped keys).resolved from API key
aiBaseUrlBase URL for AI endpoints.https://ai.onyx.dev
defaultModelFallback AI model for shorthand chat.onyx
partitionDefault partition for queries/find/delete.entity partition
requestLoggingEnabledLog HTTP requests and bodies.false
responseLoggingEnabledLog HTTP responses and bodies.false
ttlMilliseconds to cache resolved credentials.300000 (5 minutes)
retryRetry config for idempotent GET (honors Retry-After).enabled; 3 retries; 300/600/1200ms

Core CRUD

Upsert, fetch, update, and delete entities by primary key.

Kotlin
import com.onyx.cloud.api.onyx

val db = onyx.init<Any>()

val account = Account(id = "acct_1", name = "Checking", balance = 1250.0)
db.save(account)

val fetched: Account? = db.findById("acct_1")

db.save(account.copy(balance = 1400.0))

db.delete("Account", "acct_1")

Atomic Saving

Persist a parent plus related records in one call—no explicit transactions needed.

Kotlin

Cascade save

Save Account with related Transactions (all-or-none commit).

val account = Account(
  id = "acct_cascade",
  name = "Primary",
  balance = 0.0,
  transactions = listOf(
    Transaction(id = "txn_1", accountId = "acct_cascade", amount = 250.0, currency = "USD"),
    Transaction(id = "txn_2", accountId = "acct_cascade", amount = 125.0, currency = "USD"),
  )
)

val saved = db
  .cascade("transactions:Transaction(accountId, id)")
  .save(Account::class, account)

Cascade builder

Compose cascade strings fluently.

val rel = db
  .cascadeBuilder()
  .graph("transactions")
  .graphType("Transaction")
  .targetField("accountId")
  .sourceField("id")

println(rel.toString()) // transactions:Transaction(accountId, id)

Cascade string syntax

<field>:<RelatedTable>(<targetField>, <sourceField>) — field: property on the parent holding related rows; RelatedTable: table to upsert; targetField: FK on the related table; sourceField: parent field to copy.

Resolvers

Hydrate schema-defined relations inline to avoid extra round trips.

Kotlin

Fetch by id with resolver

Load a transaction and its account in one call.

val tx: Transaction? = db
  .findById<Transaction>("txn_123", resolvers = listOf("account"))

Query with resolver

Include related data while filtering the base table.

import com.onyx.cloud.api.eq

val rows = db.from<Transaction>()
  .where("status" eq "posted")
  .resolve("account")
  .list<Transaction>()

Filter by resolver field

Filter using fields exposed by the resolver.

import com.onyx.cloud.api.eq

val rows = db.from<Transaction>()
  .where("account.name" eq "Primary")
  .resolve("account")
  .list<Transaction>()

Bulk Save

Insert many records efficiently by passing a list to save.

Kotlin
val txns = listOf(
  Transaction(id = "txn_batch_1", accountId = "acct_batch", amount = 1.99, currency = "USD"),
  Transaction(id = "txn_batch_2", accountId = "acct_batch", amount = 12.5, currency = "USD"),
  Transaction(id = "txn_batch_3", accountId = "acct_batch", amount = 45.0, currency = "USD"),
  Transaction(id = "txn_batch_4", accountId = "acct_batch", amount = 7.25, currency = "USD"),
)

db.save(Transaction::class, txns)

Query & Filter

Boolean filters, ranges, text contains, ordering, and limits.

Kotlin
import com.onyx.cloud.api.*

val results = db.from<Transaction>()
  .where("status" eq "posted")
  .and("amount" gt 100.0)
  .and("createdAt" gte "2025-01-01")
  .and(contains("merchant", "aws"))
  .orderBy(desc("createdAt"))
  .limit(25)
  .list<Transaction>()

Defaults: if you omit limit() and pageSize, the API uses its server-side default page size (capped at 1000); responses include nextPage when more rows remain.

Query clauses

ClauseSignatureWhat it does
wherewhere(condition)Sets the primary filter.
andand(condition)Adds an AND condition.
oror(condition)Adds an OR condition.
orderByorderBy(asc/desc(...))Sorts results.
groupBygroupBy(...fields)Groups for aggregates.
distinctdistinct()Return unique rows.
limitlimit(n)Cap result size.
pageSizepageSize(n)Set page size for streaming/paged queries.
inPartitioninPartition(partition)Scope query to a partition.
nextPagenextPage(token)Continue a paged query.

Filters

HelperSignatureWhat it does
eq"field" eq valueEquals.
ne"field" ne valueNot equals.
gt"field" gt valueGreater than.
gte"field" gte valueGreater than or equal.
lt"field" lt valueLess than.
lte"field" lte valueLess than or equal.
betweenbetween("field", low, high)Inclusive range.
containscontains("field", text)Case-sensitive substring.
startsWithstartsWith("field", prefix)Prefix match.
endsWithendsWith("field", suffix)Suffix match.
inOpinOp("field", list)Field in list.
notInnotIn("field", list)Field not in list.
isNullisNull("field")Field is null.
notNullnotNull("field")Field is not null.
withinwithin("field", subquery)Field in subquery results.
searchsearch(lucene, minScore)Lucene predicate.

Select Query

Pick specific columns to return from a table.

Kotlin
val rows = db.select("id", "accountId", "amount", "createdAt")
  .from<Transaction>()
  .list<Map<String, Any>>()

First or Null

When you expect a single row, use firstOrNull() or its alias one().

Kotlin
import com.onyx.cloud.api.eq

val tx: Transaction? = db.from<Transaction>()
  .where("id" eq "txn_123")
  .firstOrNull()

val txOne: Transaction? = db.from<Transaction>()
  .where("id" eq "txn_123")
  .one()

Inner Queries

Filter a table using sub-selects returned from another query.

Kotlin
import com.onyx.cloud.api.*

val accounts = db.from<Account>()
  .where(
    within(
      "id",
      db.select("accountId")
        .from<Transaction>()
        .where(gt("amount", 1000.0))
    )
  )
  .list<Account>()

Update Query

Set partial updates for all rows matching a condition.

Kotlin
import com.onyx.cloud.api.eq

val updatedCount = db.from<Transaction>()
  .where("status" eq "pending")
  .and("amount" gt 100.0)
  .setUpdates("status" to "posted")
  .update()

Delete Query

Delete all rows that match a filter.

Kotlin
import com.onyx.cloud.api.eq

val deleted = db.from<Transaction>()
  .where("status" eq "archived")
  .delete()

Group By

Group results by one or more fields to segment metrics.

Kotlin
import com.onyx.cloud.api.eq

val grouped = db.select("merchant", "currency")
  .from<Transaction>()
  .where("status" eq "posted")
  .groupBy("merchant", "currency")
  .list<Map<String, Any>>()

Aggregations

Server-side rollups for dashboards and billing summaries.

Kotlin
import com.onyx.cloud.api.*

val totals = db.select(sum("amount"), "merchant")
  .from<Transaction>()
  .where("status" eq "posted")
  .list<Map<String, Any>>()

Server-side aggregate helpers

FunctionSignatureWhat it does
sumsum("field")Numeric sum of a column.
countcount("field"|"*")Row count.
avgavg("field")Arithmetic mean.
minmin("field")Smallest value.
maxmax("field")Largest value.
medianmedian("field")50th percentile.
percentilepercentile("field", p)p-th percentile (0–100).
stdstd("field")Sample standard deviation.
variancevariance("field")Sample variance.
upperupper("field")Uppercase before grouping/aggregation.
lowerlower("field")Lowercase before grouping/aggregation.
formatformat("field", "pattern")Apply Java-style format (e.g., yyyy-MM).
substringsubstring("field", from, length)Substring prior to grouping.
replacereplace("field", pattern, repl)Regex/substring replacement.

Streaming Queries

Consume large result sets incrementally and react to live query responses.

Kotlin
import com.onyx.cloud.api.eq

val events = mutableListOf<Transaction>()
val subscription = db.from<Transaction>()
  .where("status" eq "posted")
  .onItem<Transaction> { events.add(it) }
  .onItemAdded<Transaction> { events.add(it) }
  .onItemUpdated<Transaction> { events.add(it) }
  .onItemDeleted<Transaction> { events.add(it) }
  .stream<Transaction>(includeQueryResults = true, keepAlive = true)

// later
subscription.cancelAndJoin()

Pagination

Page through ordered results with stable cursors (offset-free).

Kotlin
import com.onyx.cloud.api.asc

val page1 = db.from<Transaction>()
  .orderBy(asc("createdAt"))
  .limit(50)
  .page<Transaction>()

val next = page1.nextPage
if (next != null) {
  val page2 = db.from<Transaction>()
    .orderBy(asc("createdAt"))
    .page<Transaction>(nextPage = next)
}

AI Chat

Use the AI endpoint to answer questions that reference your data.

Kotlin

Chat completions

Full request with model and messages.

val response = db.chat(
  model = "onyx",
  messages = listOf(
    AIChatMessage(role = "system", content = "You are a finance assistant."),
    AIChatMessage(role = "assistant", content = "I summarize trends each Friday."),
    AIChatMessage(role = "user", content = "Draft a status update for finance stakeholders."),
  )
)
println(response)

Streaming chat

Stream tokens as they arrive.

val stream = db.chatStream(
  model = "onyx",
  messages = listOf(AIChatMessage(role = "user", content = "List the top 3 spend categories this week."))
)
for (chunk in stream) {
  val delta = chunk.choices.firstOrNull()?.delta?.content
  if (delta != null) print(delta)
}

Shorthand chat (string in, string out)

Quick one-liner for common prompts.

val summary = db.chat("Summarize yesterday's transactions")

List available models

Discover model IDs before picking one.

val models = db.getModels()
models.data.forEach { println(it.id) }

Get model details

Inspect a specific model's capabilities and limits.

val model = db.getModel("onyx")
println(model)

Request script approval

Validate a mutation script before execution.

val approval = db.requestScriptApproval(
  script = "db.save({ id: 'acct_1', name: 'Checking' })"
)
println(approval)

Documents

Upload binary files with metadata, fetch with optional resizing, or delete stored documents.

Kotlin

Save a document

Stores metadata in the DB and writes bytes to the database’s _documents path.

val payload = "hello".toByteArray()
val doc = OnyxDocument(
  documentId = "hello.txt",
  path = "/docs/hello.txt",
  mimeType = "text/plain",
  content = payload
)
db.saveDocument(doc)

Get a document (optional resize for images)

Fetches by documentId; width/height resize images on the fly.

val doc = db.getDocument("hello.txt")

Delete a document

Removes the file and its metadata.

db.deleteDocument("hello.txt")

Storage & search

Files are written to your database’s filesystem under _documents/; only metadata (path, mimeType, timestamps) is stored in the Document record. If you provide plaintext content, it is chunked into Lucene-indexed parts so full-text search can find the document.

Secrets

Manage encrypted secrets stored per database; db calls never persist plaintext.

Kotlin

List secrets (metadata only)

Returns keys, purposes, and timestamps—no values.

val secrets = db.listSecrets()
println(secrets)

Fetch a secret value

Decrypts and returns the plaintext for a single key.

val secret = db.getSecret("stripe_api_key")

Create or rotate a secret

Stores the value encrypted at rest; re-encrypts on each update.

db.putSecret(
  key = "stripe_api_key",
  value = "sk_live_...",
  purpose = "Stripe server key"
)

Delete a secret

Removes the record from the database.

db.deleteSecret("stripe_api_key")

How Onyx secures secrets

  • Each secret is encrypted with a random AES-256-GCM key; that key is wrapped using the database’s 4096-bit RSA public key. Only ciphertext and wrapped keys are stored.
  • Per-database RSA private keys are themselves encrypted with a master key.
  • API routes require valid database credentials; plaintext values are only returned on authenticated GET /secret/{key} and are never persisted decrypted.
  • Back up the keystore directory (secret-keystore) together with the master key to preserve decryption ability.

Schema

Fetch, diff, validate, and publish schema revisions.

Kotlin
val current = db.getSchema() ?: emptyMap<String, Any>()
val next = current.toMutableMap().apply {
  // modify entities/attributes here
  put("revisionDescription", "Describe your change")
}

val diff = db.diffSchema(next)
val validation = db.validateSchema(next)
if (validation.valid == true) {
  db.updateSchema(next, publish = true)
}

Need the JSON shape for entities, attributes, and resolvers? See Schema Example.

Next Steps