SDK Overview
Choose an SDK, understand the common API surface, and start reading secrets.
SikkerKey SDKs provide read-only access to secrets from your application. Every SDK authenticates using the same Ed25519 machine identity as the CLI. No API keys, no tokens, no sessions.
All secret management (create, update, rotate, delete) is done through the dashboard. SDKs and the CLI are read-only — they fetch secrets, they don't modify them.
Choose Your SDK
All five SDKs share the same API surface and behavior. Pick the one that matches your runtime. All SDKs are open source under the MIT license on GitHub.
Common API
Every SDK exposes the same core operations:
| Operation | What it does |
|---|---|
getSecret(id) | Read a single-value secret |
getFields(id) | Read a structured secret as key-value pairs |
getField(id, field) | Read one field from a structured secret |
listSecrets() | List all secrets this machine can access |
listSecretsByProject(projectId) | List secrets in a specific project |
export(projectId?) | Export all secrets as a flat key-value map |
listVaults() | List vault IDs registered on this machine |
watch(id, callback) | Watch a secret for changes in near real-time |
unwatch(id) | Stop watching a secret |
setPollInterval(seconds) | Set the poll interval (minimum 10 seconds) |
close() | Stop all watches and shut down polling |
Naming conventions vary by language (getSecret in Kotlin/Node, get_secret in Python, GetSecret in Go/.NET), but the behavior is identical.
Identity Resolution
The SDK finds the machine's Ed25519 keypair automatically. Resolution order:
- Explicit vault ID —
SikkerKey("vault_abc123")looks up~/.sikkerkey/vaults/vault_abc123/identity.json - Explicit path —
SikkerKey("/path/to/identity.json")uses a file path directly - Environment variable —
SIKKERKEY_IDENTITYpoints to anidentity.jsonfile - Auto-detect — if exactly one vault directory exists, uses it automatically
The base directory (~/.sikkerkey/) can be overridden with the SIKKERKEY_HOME environment variable. The vault_ prefix is added automatically if not present.
Authentication
Every request is signed with the machine's Ed25519 private key:
- Build the payload:
{method}:{path}:{timestamp}:{nonce}:{bodyHash} - Sign with the private key
- Send four headers:
X-Machine-Id,X-Timestamp,X-Nonce,X-Signature - Server verifies the signature against the stored public key
No tokens are stored, transmitted, or refreshed. Every request is independently authenticated. HTTPS is enforced for all non-localhost connections.
Retry Behavior
All SDKs automatically retry on:
- 429 Too Many Requests — rate limited
- 503 Service Unavailable — server sealed or temporarily down
Retry schedule: 1s, 2s, 4s (exponential backoff, max 3 retries). Each retry generates a fresh timestamp and nonce. Network errors are also retried.
Error Handling
All SDKs use a typed exception hierarchy:
| Exception | HTTP Status | Meaning |
|---|---|---|
AuthenticationError | 401 | Invalid signature or unknown machine |
AccessDeniedError | 403 | Machine not approved, disabled, or no grant |
NotFoundError | 404 | Secret does not exist |
ConflictError | 409 | Invalid operation |
RateLimitedError | 429 | Too many requests (retried automatically) |
ServerSealedError | 503 | Server needs unseal (retried automatically) |
ConfigurationError | — | Identity file missing, key not found |
SecretStructureError | — | Secret is not a JSON object (getFields) |
FieldNotFoundError | — | Field not in structured secret (getField) |
Exception class names vary by language convention (e.g. NotFoundError in Node.js, NotFoundException in Kotlin, NotFoundError in Go).
Watching for Changes
All SDKs can watch secrets for changes in near real-time. When a secret is rotated, updated, deleted, or access is revoked, a callback fires with the new value. Polling happens in the background -- your application is never blocked.
// Node.js example -- all SDKs have the same API
sk.watch('sk_db_credentials', (event) => {
if (event.status === 'changed') {
db.reconfigure({
username: event.fields.username,
password: event.fields.password,
})
}
})
The SDK polls the server every 15 seconds (configurable, minimum 10). When a change is detected, the SDK fetches the new value through the normal authenticated path -- every read is audited. Structured secrets are automatically parsed into fields.
Statuses:
| Status | Meaning |
|---|---|
changed | Secret was updated or rotated. New value and parsed fields are provided. |
deleted | Secret was deleted. Watch is automatically removed. |
access_denied | Machine no longer has access. Watch is automatically removed. |
error | Failed to fetch the updated value. Error message provided. |
See individual SDK pages for language-specific examples.
Multi-Vault
A machine registered with multiple vaults uses a separate keypair per vault:
const prod = SikkerKey.create('vault_production')
const staging = SikkerKey.create('vault_staging')
const dbPass = await prod.getSecret('sk_db_prod')
const testKey = await staging.getSecret('sk_test_key')
Each vault is fully isolated — different keypairs, different encryption keys, different access grants.
Export and Environment Injection
All SDKs can export secrets as a flat key-value map:
const env = await sk.export()
// { API_KEY: "sk-live-...", DB_CREDS_HOST: "db.example.com", DB_CREDS_PASSWORD: "s3cret" }
Structured secrets are flattened: a secret named DB Creds with fields host and password becomes DB_CREDS_HOST and DB_CREDS_PASSWORD.
For CLI-based injection, use sikkerkey run -- ./your-app which exports all secrets as environment variables into the child process.
Environment Variables
| Variable | Description |
|---|---|
SIKKERKEY_IDENTITY | Path to identity.json — overrides vault lookup |
SIKKERKEY_HOME | Base config directory (default: ~/.sikkerkey) |
SIKKERKEY_VAULT | Vault ID hint (used by some SDKs for auto-detection) |