Operations Reference
This page lists all available Operations API operations, grouped by category. Each entry links to the feature section where the full documentation lives.
For endpoint and authentication setup, see the Operations API Overview.
Databases & Tables
Operations for managing databases, tables, and attributes.
Detailed documentation: Database Overview
| Operation | Description | Role Required |
|---|---|---|
describe_all | Returns definitions of all databases and tables, with record counts | any |
describe_database | Returns all table definitions for a specified database | any |
describe_table | Returns the definition of a specified table | any |
create_database | Creates a new database | super_user |
drop_database | Drops a database and all its tables/records | super_user |
create_table | Creates a new table with optional schema and expiration | super_user |
drop_table | Drops a table and all its records | super_user |
create_attribute | Adds a new attribute to a table | super_user |
drop_attribute | Removes an attribute and all its values from a table | super_user |
describe_all
Returns the definitions of all databases and tables within the database. Record counts above 5000 records are estimated; the response includes estimated_record_range when estimated. To force an exact count (requires full table scan), include "exact_count": true.
{ "operation": "describe_all" }
describe_database
Returns all table definitions within the specified database.
{ "operation": "describe_database", "database": "dev" }
describe_table
Returns the definition of a specific table.
{ "operation": "describe_table", "table": "dog", "database": "dev" }
create_database
Creates a new database.
{ "operation": "create_database", "database": "dev" }
drop_database
Drops a database and all its tables/records. Supports "replicated": true to propagate to all cluster nodes.
{ "operation": "drop_database", "database": "dev" }
create_table
Creates a new table. Optional fields: database (defaults to data), attributes (array defining schema), expiration (TTL in seconds).
{
"operation": "create_table",
"database": "dev",
"table": "dog",
"primary_key": "id"
}
drop_table
Drops a table and all associated records. Supports "replicated": true.
{ "operation": "drop_table", "database": "dev", "table": "dog" }
create_attribute
Creates a new attribute within a table. Harper auto-creates attributes on insert/update, but this can be used to pre-define them (e.g., for role-based permission setup).
{
"operation": "create_attribute",
"database": "dev",
"table": "dog",
"attribute": "is_adorable"
}
drop_attribute
Drops an attribute and all its values from the specified table.
{
"operation": "drop_attribute",
"database": "dev",
"table": "dog",
"attribute": "is_adorable"
}
NoSQL Operations
Operations for inserting, updating, deleting, and querying records using NoSQL.
Detailed documentation: REST Querying Reference
| Operation | Description | Role Required |
|---|---|---|
insert | Inserts one or more records | any |
update | Updates one or more records by primary key | any |
upsert | Inserts or updates records | any |
delete | Deletes records by primary key | any |
search_by_id | Retrieves records by primary key | any |
search_by_value | Retrieves records matching a value on any attribute | any |
search_by_conditions | Retrieves records matching complex conditions with sorting and pagination | any |
insert
Inserts one or more records. If a primary key is not provided, a GUID or auto-increment value is generated.
{
"operation": "insert",
"database": "dev",
"table": "dog",
"records": [{ "id": 1, "dog_name": "Penny" }]
}
update
Updates one or more records. Primary key must be supplied for each record.
{
"operation": "update",
"database": "dev",
"table": "dog",
"records": [{ "id": 1, "weight_lbs": 38 }]
}
upsert
Updates existing records and inserts new ones. Matches on primary key if provided.
{
"operation": "upsert",
"database": "dev",
"table": "dog",
"records": [{ "id": 1, "weight_lbs": 40 }]
}
delete
Deletes records by primary key values.
{
"operation": "delete",
"database": "dev",
"table": "dog",
"ids": [1, 2]
}
search_by_id
Returns records matching the given primary key values. Use "get_attributes": ["*"] to return all attributes.
{
"operation": "search_by_id",
"database": "dev",
"table": "dog",
"ids": [1, 2],
"get_attributes": ["dog_name", "breed_id"]
}
search_by_value
Returns records with a matching value on any attribute. Supports wildcards (e.g., "Ky*").
{
"operation": "search_by_value",
"database": "dev",
"table": "dog",
"attribute": "owner_name",
"value": "Ky*",
"get_attributes": ["id", "dog_name"]
}
search_by_conditions
Returns records matching one or more conditions. Supports operator (and/or), offset, limit, nested conditions groups, and sort with multi-level tie-breaking.
{
"operation": "search_by_conditions",
"database": "dev",
"table": "dog",
"operator": "and",
"limit": 10,
"get_attributes": ["*"],
"conditions": [{ "attribute": "age", "comparator": "between", "value": [5, 8] }]
}
Bulk Operations
Operations for bulk import/export of data.
Detailed documentation: Database Jobs
| Operation | Description | Role Required |
|---|---|---|
export_local | Exports query results to a local file in JSON or CSV | super_user |
csv_data_load | Ingests CSV data provided inline | any |
csv_file_load | Ingests CSV data from a server-local file path | any |
csv_url_load | Ingests CSV data from a URL | any |
export_to_s3 | Exports query results to AWS S3 | super_user |
import_from_s3 | Imports CSV or JSON data from AWS S3 | any |
delete_records_before | Deletes records older than a given timestamp (local node only) | super_user |
All bulk import/export operations are asynchronous and return a job ID. Use get_job to check status.
export_local
Exports query results to a local path on the server. Formats: json or csv.
{
"operation": "export_local",
"format": "json",
"path": "/data/",
"search_operation": { "operation": "sql", "sql": "SELECT * FROM dev.dog" }
}
csv_data_load
Ingests inline CSV data. Actions: insert (default), update, upsert.
{
"operation": "csv_data_load",
"database": "dev",
"table": "dog",
"action": "insert",
"data": "id,name\n1,Penny\n"
}
csv_file_load
Ingests CSV from a file path on the server running Harper.
{
"operation": "csv_file_load",
"database": "dev",
"table": "dog",
"file_path": "/home/user/imports/dogs.csv"
}
csv_url_load
Ingests CSV from a URL.
{
"operation": "csv_url_load",
"database": "dev",
"table": "dog",
"csv_url": "https://example.com/dogs.csv"
}
export_to_s3
Exports query results to an AWS S3 bucket as JSON or CSV.
{
"operation": "export_to_s3",
"format": "json",
"s3": {
"aws_access_key_id": "YOUR_KEY",
"aws_secret_access_key": "YOUR_SECRET",
"bucket": "my-bucket",
"key": "dogs.json",
"region": "us-east-1"
},
"search_operation": { "operation": "sql", "sql": "SELECT * FROM dev.dog" }
}
import_from_s3
Imports CSV or JSON from an AWS S3 bucket. File must include a valid .csv or .json extension.
{
"operation": "import_from_s3",
"database": "dev",
"table": "dog",
"s3": {
"aws_access_key_id": "YOUR_KEY",
"aws_secret_access_key": "YOUR_SECRET",
"bucket": "my-bucket",
"key": "dogs.csv",
"region": "us-east-1"
}
}
delete_records_before
Deletes records older than the specified timestamp from the local node only. Clustered nodes retain their data.
{
"operation": "delete_records_before",
"date": "2021-01-25T23:05:27.464",
"schema": "dev",
"table": "dog"
}
SQL Operations
Operations for executing SQL statements.
Harper SQL is intended for data investigation and use cases where performance is not a priority. For production workloads, use NoSQL or REST operations. SQL performance optimizations are on the roadmap.
Detailed documentation: SQL Reference
| Operation | Description | Role Required |
|---|---|---|
sql | Executes a SQL SELECT, INSERT, UPDATE, or DELETE statement | any |
sql
Executes a standard SQL statement.
{ "operation": "sql", "sql": "SELECT * FROM dev.dog WHERE id = 1" }
Users & Roles
Operations for managing users and role-based access control (RBAC).
Detailed documentation: Users & Roles Operations
| Operation | Description | Role Required |
|---|---|---|
list_roles | Returns all roles | super_user |
add_role | Creates a new role with permissions | super_user |
alter_role | Modifies an existing role's permissions | super_user |
drop_role | Deletes a role (role must have no associated users) | super_user |
list_users | Returns all users | super_user |
user_info | Returns data for the authenticated user | any |
add_user | Creates a new user | super_user |
alter_user | Modifies an existing user's credentials or role | super_user |
drop_user | Deletes a user | super_user |
list_roles
Returns all roles defined in the instance.
{ "operation": "list_roles" }
add_role
Creates a new role with the specified permissions. The permission object maps database names to table-level access rules (read, insert, update, delete). Set super_user: true to grant full access.
{
"operation": "add_role",
"role": "developer",
"permission": {
"super_user": false,
"dev": {
"tables": {
"dog": { "read": true, "insert": true, "update": true, "delete": false }
}
}
}
}
alter_role
Modifies an existing role's name or permissions. Requires the role's id (returned by list_roles).
{
"operation": "alter_role",
"id": "f92162e2-cd17-450c-aae0-372a76859038",
"role": "senior_developer",
"permission": {
"super_user": false,
"dev": {
"tables": {
"dog": { "read": true, "insert": true, "update": true, "delete": true }
}
}
}
}
drop_role
Deletes a role. The role must have no associated users before it can be dropped.
{ "operation": "drop_role", "id": "f92162e2-cd17-450c-aae0-372a76859038" }
list_users
Returns all users.
{ "operation": "list_users" }
user_info
Returns data for the currently authenticated user.
{ "operation": "user_info" }
add_user
Creates a new user. username cannot be changed after creation. password is stored encrypted.
{
"operation": "add_user",
"role": "developer",
"username": "hdb_user",
"password": "password",
"active": true
}
alter_user
Modifies an existing user's password, role, or active status. All fields except username are optional.
{
"operation": "alter_user",
"username": "hdb_user",
"password": "new_password",
"role": "senior_developer",
"active": true
}
drop_user
Deletes a user by username.
{ "operation": "drop_user", "username": "hdb_user" }
See Users & Roles Operations for full documentation including permission object structure.
Token Authentication
Operations for JWT token creation and refresh.
Detailed documentation: JWT Authentication
| Operation | Description | Role Required |
|---|---|---|
create_authentication_tokens | Creates an operation token and refresh token for a user | none (unauthenticated) |
refresh_operation_token | Creates a new operation token from a refresh token | any |
create_authentication_tokens
Does not require prior authentication. Returns operation_token (short-lived JWT) and refresh_token (long-lived JWT).
{
"operation": "create_authentication_tokens",
"username": "my-user",
"password": "my-password"
}
refresh_operation_token
Creates a new operation token from an existing refresh token.
{
"operation": "refresh_operation_token",
"refresh_token": "EXISTING_REFRESH_TOKEN"
}
Components
Operations for deploying and managing Harper components (applications, plugins).
Detailed documentation: Components Overview
| Operation | Description | Role Required |
|---|---|---|
add_component | Creates a new component project from a template | super_user |
deploy_component | Deploys a component via payload (tar) or package reference (NPM/GitHub) | super_user |
revert_component | Puts a component's retained previous version back in service | super_user |
package_component | Packages a component project into a base64-encoded tar | super_user |
drop_component | Deletes a component or a file within a component | super_user |
get_components | Lists all component files and config | super_user |
get_component_file | Returns the contents of a file within a component | super_user |
set_component_file | Creates or updates a file within a component | super_user |
list_deployments | Lists deployment records with optional filters | super_user |
get_deployment | Fetches a single deployment record by ID; supports SSE streaming | super_user |
get_deployment_payload | Returns the tarball stored for a deployment | super_user |
delete_deployment_payload | Removes the stored tarball to free space | super_user |
add_ssh_key | Adds an SSH key for deploying from private repositories | super_user |
update_ssh_key | Updates an existing SSH key | super_user |
delete_ssh_key | Deletes an SSH key | super_user |
list_ssh_keys | Lists all configured SSH key names | super_user |
set_ssh_known_hosts | Overwrites the SSH known_hosts file | super_user |
get_ssh_known_hosts | Returns the contents of the SSH known_hosts file | super_user |
install_node_modules | (Deprecated) Run npm install on component projects | super_user |
deploy_component
Changed in: v5.3.0
Deploys a component. The package option accepts any valid NPM reference including GitHub repos (HarperDB/app#semver:v1.0.0), tarballs, or NPM packages. The payload option accepts a base64-encoded tar string from package_component. Supports "replicated": true and "restart": true or "restart": "rolling".
Across a cluster, deploy_component runs in two phases separated by an all-nodes staging barrier:
- Stage — the incoming version is downloaded/packed, extracted, and
npm installed into a hidden staging directory on every node, without touching the live component. - Activate — only after every node reports a successful stage does any node atomically swap the staged copy into the live path.
The barrier is what the two phases buy you: if a node can't fetch the package or fails npm install, it fails during staging and the live component is left untouched on every node, rather than leaving part of the cluster half-updated. That is the class of failure — by far the most common one — that a two-phase deploy eliminates.
It is not, however, all-or-nothing at go-live. Activation still happens per node, so a swap that fails on one node after others have already gone live leaves the cluster running mixed versions until you resolve it, and there is deliberately no automatic rollback — see activation failures below. The request and response shape are unchanged; the two phases are internal.
Two-phase deploy requires operation replication and replication of the system database, because the staging barrier is coordinated through a replicated deployment row.
A deploy on a cluster where system is excluded from replication silently takes the legacy one-shot path instead: no staging barrier, and no retained previous version for revert_component to roll back to. The staged-phase parameters are not silently downgraded that way — activate: false and deployment_id are rejected with an explanatory error rather than going live unexpectedly, as is two_phase: true itself.
Deploying a brand-new component without a restart ("restart": false, or omitting restart) marks a restart as required — get_status reports restartRequired: true, and requests to the new component's routes return an actionable 404 explaining that a restart is needed. A never-loaded component can't serve its routes until Harper restarts, so this makes that state visible instead of silent. Each node reports this for itself, since whether the component was already active can differ per node. Redeploying a component that is already live does not set the flag: that component's own file watcher requests a restart only if the update actually needs one.
Additional parameters:
urlPath— the HTTP URL path the component is mounted at (e.g."/api/v2"). Must not contain..or.path segments. Persisted on the component's root-config entry; see HTTP middleware routing.hostAdded in: v5.2.0 — the virtual hostname the component is served on (e.g."api.example.com"). Must be a bare hostname or IPv6 literal — no scheme, port, path, or brackets. Persisted alongsideurlPath.install_allow_scripts— set totrueto allow npm pre/post install scripts (disabled by default)activate— set tofalseto stage only and stop before go-live. The build is prepared and verified on every node and the response returns adeployment_idin astagedstate; nothing goes live. Activate it later by callingdeploy_componentagain with thatdeployment_id(see below). Useful for pre-staging a release and flipping it live in a separate, fast step.deployment_id— activate a previously-staged deployment (from anactivate: falsecall). Normally nothing is re-fetched or re-installed: the build staged earlier is swapped live cluster-wide. If a node's staged tree is missing or incomplete by then — a restart or disk repair between staging and activation — that node re-sources the payload and rebuilds before swapping, so activation can take noticeably longer there and can fail on a package whose source or credential is no longer reachable.projectis still required. For apackagedeploy you do not need to repeatpackagehere: the identifier and credential references recorded when it was staged are recovered from the deployment and persisted to root config at activation, on every node — so a later restart or a newly joined peer reinstalls the version you activated.ignore_replication_errors— treat replication/peer failures as non-fatal (best-effort deploy to a partially-available cluster). This also opts out of the stage barrier. Applies to both a full deploy and adeployment_idactivate.deployment_timeout— per-deploy budget (ms) for peers to receive the replicated deployment row; defaults to 120000.two_phase— set tofalseto force the legacy single-phase (in-place) deploy instead of stage-then-activate.credentials— credentials for installing a component from a private npm registry or private git repository (see below)
urlPath and host both require package and are rejected on a payload-only deploy. To mount a payload-deployed component, add host/urlPath to its entry in the root harper-config.yaml instead.
Deploy modes
activate, deployment_id, two_phase, and replicated are not independent knobs — a request that asks for a staged phase without the machinery to support it is rejected rather than quietly doing something else. The valid combinations:
| Request | Result |
|---|---|
No mode parameters, system replicated | Two-phase stage → barrier → activate |
No mode parameters, system not replicated | Legacy one-shot deploy, no retained previous version |
two_phase: false | Legacy one-shot deploy, no retained previous version |
replicated: false | Legacy one-shot deploy on this node only, no retained previous version |
ignore_replication_errors: true | Stage barrier not enforced — a node that fails to stage no longer blocks activation |
activate: false | Stage only; returns a staged deployment_id |
deployment_id | Activate that staged deployment cluster-wide |
activate: false or deployment_id, with two_phase: false, replicated: false, or system not replicated | Rejected |
two_phase: true with replicated: false or system not replicated | Rejected |
revert_on_failure (any value) | Rejected — see activation failures |
revert_on_failure was part of an earlier draft of this operation and is now refused outright rather than accepted and ignored, so a caller that was relying on it finds out.
Activation failures
If the activate phase fails on some nodes after others have already gone live, the deploy reports the split nodes and the deployment stays in an activating state rather than being rolled back automatically. Recover by rolling forward (stage and activate a known-good version) or by rolling back explicitly with revert_component.
There is deliberately no automatic rollback. Once a node is past the activation barrier, a peer reporting failure does not prove that peer did not activate — it can complete its swap and then fail, or die before replying — so automatically reverting "the failed nodes" risks rolling an untouched node an extra version back and leaving the cluster split three ways instead of converging it. A human deciding to roll forward or back is the only step that reliably converges the cluster.
Deploy credentials (credentials)
When a component is installed from a private source, credentials supplies the authentication. It is an array of entries; each entry is one of two kinds, identified by its key:
- npm registry auth — an entry with a
registrykey, applied to a private npm registry. - git host auth — an entry with a
hostkey, applied to a private git repository fetched by reference (e.g.package: "github:my-org/my-app#semver:v1.2.3").
An entry provides its credential exactly one of two ways — a literal token, or a secret reference:
| Field | Kind | Description |
|---|---|---|
registry | npm | The registry URL or host the credential applies to. Required for an npm entry. |
scope | npm | Optional npm @scope (e.g. "@my-org") the entry applies to; omit to set the default registry. |
host | git | The bare git host the credential applies to (e.g. "github.com"). Required for a git entry. |
username | git | Optional git HTTPS username. Defaults to x-access-token (GitHub); GitLab uses oauth2, Bitbucket x-token-auth. |
token | both | A literal auth token, or |
secret | both | The name of an hdb_secret row to resolve the token from. |
A provided token is not treated as ephemeral: Harper ingests it into the encrypted secrets store and references it everywhere, so package-reference deploys keep working through rollback, reboot, and new peers joining — without re-supplying the token. The token is encrypted at rest, stripped from the operation before replication and from the operations log, and only ever crosses the cluster as ciphertext. A git-host token is additionally served to git from memory (via a credential helper) — it is never written to a file or into a URL. Using a secret reference names an existing store row directly. Ingesting a token requires custody on the deploying node; on OSS core without custody, a literal token falls back to a transient, this-node-only credential (not persisted or replicated).
Ingested tokens are stored under a derived name granted to the component — deploy.<component>.<registry> for a registry entry, deploy.<component>.git.<host> for a git entry — so re-deploying with a rotated token idempotently updates the same row.
Private npm registry:
{
"operation": "deploy_component",
"project": "my-app",
"package": "npm:@my-org/my-app@1.2.3",
"credentials": [{ "registry": "https://registry.my-org.com", "scope": "@my-org", "token": "npm_..." }]
}
Private git repository (token resolved from an existing secret):
{
"operation": "deploy_component",
"project": "my-app",
"package": "github:my-org/my-app#semver:v1.2.3",
"credentials": [{ "host": "github.com", "secret": "deploy.my-app.git.github_com" }]
}
credentials replaces the earlier registryAuth field (renamed while the feature was in alpha, before it grew to carry git-host credentials). registryAuth is now rejected with an error directing you to credentials.
A normal deploy (stage + activate):
{
"operation": "deploy_component",
"project": "my-app",
"package": "my-org/my-app#semver:v1.2.3",
"replicated": true,
"restart": "rolling"
}
Response — a rolling restart is driven by a separate replicated job, so its id comes back as restartJobId:
{
"deployment_id": "a3f8c2d1...",
"restartJobId": "b7d41e09...",
"message": "Successfully deployed: my-app, restarting Harper"
}
Without a restart ("restart": false, or omitted) the response carries no restartJobId and the message is just Successfully deployed: my-app.
Stage now, activate later:
Stage request (activate: false):
{ "operation": "deploy_component", "project": "my-app", "package": "my-org/my-app#semver:v1.2.3", "activate": false }
Stage response (nothing is live yet; note the staged marker and the deployment_id):
{ "deployment_id": "a3f8c2d1...", "project": "my-app", "staged": true, "message": "Staged component: my-app" }
Activation request (take the staged build live by passing its deployment_id):
{ "operation": "deploy_component", "project": "my-app", "deployment_id": "a3f8c2d1...", "restart": "rolling" }
revert_component
Added in: v5.3.0
Puts a component's retained previous version back in service across the cluster. This is a fast rollback that resolves no package, decrypts no secret, downloads no artifact and runs no install — every node already has the bytes, and the swap is a single atomic directory rename per node.
This is the rollback for the bad release you just shipped: deploy a new version, run your own health checks against it, and put the old one back if you are not happy — even when the cluster otherwise looks healthy.
Only a two-phase activation retains a previous version. The retained copy is created by the activate phase, so revert_component can only roll back to a version that went live that way.
A version deployed with two_phase: false, or deployed on a cluster where the system database is excluded from replication, leaves nothing to revert to — and the call fails, no matter how many times that component has been deployed. If rollback matters, confirm the deploy took the two-phase path rather than assuming repeated deploys have built up a rollback target.
to_deployment_id is required, and names the deployment you expect to be live once the call returns:
{
"operation": "revert_component",
"project": "my-app",
"to_deployment_id": "a3f8c2d1-...",
"restart": "rolling"
}
Naming the target is what makes the operation safe to retry. If that version is already live, the call succeeds without changing anything — so a client that loses the response and retries cannot flip the rejected release back in. If it matches the retained previous version, the swap happens and the version it displaced becomes the new retained previous, so an explicitly targeted revert of a revert rolls forward again.
| Parameter | Description |
|---|---|
project | Required. The component to revert. |
to_deployment_id | Required. The deployment you expect to be live afterwards. list_deployments reports it, and deploy_component returns it. |
restart | true to restart immediately, or "rolling" for a rolling restart. Optional — omitted, the files are swapped but Harper is not restarted. |
ignore_replication_errors | Treat peer failures as non-fatal. |
deployment_timeout | Per-operation budget (ms) for peers. |
force | Permit the operation on a protected core component name. Does not relax the to_deployment_id checks. |
restart being optional matters more here than on a deploy: a reverted component whose code is already loaded keeps serving the version you just rolled away from until something restarts it. Pass restart: "rolling" unless you are deliberately batching the restart yourself.
The response reports reverted (false when the target was already live), to_deployment_id, and from_deployment_id — the version taken out of service, which is also recorded as rollback_of on the new hdb_deployment row for the audit trail.
A revert needs no source credential. It puts the retained build back without re-fetching from the origin, so it works even when the token or deploy key that installed the current version has since expired or been revoked — which is often the situation you are in when you need to roll back.
Only the immediately previous version is retained, so revert_component reaches back exactly one activation. It fails with "no previous version is retained" whenever there is no retained copy — a component deployed only once, or one whose deploys took the one-shot path described above — and refuses a to_deployment_id that is neither live nor the retained previous, naming what the component can actually be reverted to. To return to an older version, redeploy it with deploy_component — that is a deploy, not a revert.
Reverting also rewrites the component's stored package: reference in harperdb-config.yaml and its entry in the boot-time application lock, as part of the same operation. So a revert is a config-level rollback too: a node provisioned after the revert — a newly joined peer, or an existing node whose components directory is rebuilt — installs the version the cluster is actually running, not the one you reverted away from. Reverting away from a package deploy to a payload-deployed version removes the package reference entirely, for the same reason.
Deployment Operations
Harper records every deploy_component call in the system.hdb_deployment table, capturing the full lifecycle of a deployment including phase transitions (stage → activate → restart → success/failed, or prepare → replicate → restart on the legacy single-phase path), per-node outcomes, and a bounded event log of install output.
Staged-build retention. Deployments staged with activate: false leave their built files on disk until they are activated. Harper keeps only the most recent staged builds per component (default 5, configurable via the deployment_stagingRetention_maxCount configuration option); older not-yet-activated staged builds are evicted automatically when a new stage lands. Activating a deployment_id that has aged out of this window fails with "no staged build found."
Payload retention. The hdb_deployment records themselves are always retained as the audit trail — retention only ever reclaims the stored tarball (payload_blob), never the row. Two configuration options bound it, and they answer different questions:
| Option | Default | Effect |
|---|---|---|
deployment_payloadRetention_maxSize | 10 MiB | Reclaims this deploy's tarball right after it succeeds, if the tarball was larger than this. Bounds any single payload. |
deployment_payloadRetention_maxCount | 1 | Keeps at most this many stored tarballs per project, newest first, dropping the rest after a successful deploy. Bounds total. |
The default of maxCount: 1 means only the current version's tarball is kept. It is deliberately conservative: retained payloads share the instance's disk with your own data, so several copies of a large application payload can quietly consume quota. Raise it if you want a wider window of deployments whose payload is still downloadable; set it to 0 to keep none.
Pruning is automatic and best-effort — it never fails a deploy — and is skipped when a peer failed, since the older payloads are still the retry artifact in that case. A deployment whose payload has been reclaimed (automatically, or explicitly via delete_deployment_payload) reports payload_blob_present: false and can no longer serve get_deployment_payload; everything else about the record stays intact.
list_deployments
Returns a list of deployment records, newest first. All filter parameters are optional.
| Parameter | Type | Description |
|---|---|---|
project | string | Filter to a specific component project |
status | string | Filter by status (see below) |
since | number | Start of time range (Unix timestamp ms) |
until | number | End of time range (Unix timestamp ms) |
limit | number | Maximum number of results (default: 100) |
offset | number | Pagination offset |
{
"operation": "list_deployments",
"project": "my-app",
"status": "success",
"limit": 20
}
Response includes a deployments array and a total count. The payload_blob field is stripped from list responses for size; use get_deployment_payload to retrieve the tarball.
Deployment statuses fall into three groups:
- Terminal —
success,failed,rolled_back. The deploy is over. Only these count as terminal internally, which is what gatesget_deployment_payloadand makes a payload eligible for retention pruning. - Resting —
staged. Anactivate: falsestage-and-stop, waiting to be activated or to age out of the staging-retention window. It is finished but not terminal, so its payload is deliberately still held: it is the source the pending activation needs. - In flight —
pending,extracting,installing,staging,loading,replicating,activating,reverting,restarting. The phase the deployment is currently in; a record only stays in one of these while the deploy is running.
get_deployment
Returns a single deployment record by deployment_id. When called on an in-progress deployment via a request that accepts text/event-stream, the response streams live phase events and install output as Server-Sent Events, replaying the buffered event log then tailing until the deployment reaches a terminal status.
{
"operation": "get_deployment",
"deployment_id": "a3f8c2d1..."
}
The deployment record includes:
| Field | Description |
|---|---|
deployment_id | Unique identifier (content hash) |
project | Component project name |
package_identifier | Package reference or payload for tar uploads |
status | Any of the values listed under list_deployments — pending, extracting, installing, staging, staged, loading, replicating, activating, reverting, restarting, success, failed, or rolled_back |
phase | Current lifecycle phase: stage, load, activate, restart (or legacy prepare, replicate) |
event_log | Bounded log of install output and phase transitions (up to 200 entries) |
peer_results | Per-node outcome map for replicated deployments |
payload_hash | SHA-256 hash of the deployment tarball |
payload_size | Byte size of the deployment tarball |
started_at | Timestamp when deployment began |
completed_at | Timestamp when deployment finished |
user | User who initiated the deployment |
rollback_of | deployment_id of the deployment this rolls back, if applicable |
error | Error message for failed deployments |
get_deployment_payload
Returns the raw tarball for a deployment. Useful for inspecting or re-deploying a specific version.
{
"operation": "get_deployment_payload",
"deployment_id": "a3f8c2d1..."
}
The response is the raw tarball bytes (Content-Type: application/octet-stream, with a Content-Disposition download filename) - not JSON and not base64-encoded, so payloads of any size stream without inflation. Returns 404 if the deployment does not exist or its payload has already been reclaimed (by payload retention or delete_deployment_payload).
Unlike most other super_user operations, this check is enforced directly in the handler and cannot be satisfied by granting the operation through a role's operations allowlist - only an actual super_user role can call it.
delete_deployment_payload
Removes the tarball blob from a deployment record. The deployment record itself is retained; only the binary payload is deleted. Use this to reclaim storage after confirming a deployment is stable. The deletion replicates, so one call frees the payload's storage on every node in the cluster.
{
"operation": "delete_deployment_payload",
"deployment_id": "a3f8c2d1..."
}
Response:
{
"message": "Deleted payload for deployment 'a3f8c2d1...'",
"deployment_id": "a3f8c2d1...",
"freed_bytes": 52428800
}
The deployment must be in a terminal status (success, failed, or rolled_back); deleting the payload of an in-progress deployment fails with 409, since its payload may still be replicating to peers. Deleting an already-reclaimed payload succeeds with freed_bytes: 0 (the operation is idempotent). A payload_dropped entry recording the deleting user is appended to the deployment's event_log.
add_ssh_key
Adds an SSH key (must be ed25519) for authenticating deployments from private repositories. Supply the private key with key, or omit it and pass generate: true to have Harper mint the keypair itself.
list_ssh_keys and the logs never return key material.
The stored private key is encrypted at rest and crosses the cluster as ciphertext when secret custody is configured. Custody is present by default — the file tier generates a cluster keypair on first boot — so this is the normal case.
On a node with no secret custody registered, add_ssh_key stores and replicates the private key in plaintext. It logs a WARN saying so and the operation still succeeds, because SSH keys predate custody and must keep working on a node that has none.
That means encryption at rest is a property of your configuration, not a guarantee of the operation. If you are relying on it — and generate: true in particular reads as though the key can never be exposed — verify secretCustody is configured on every node in the cluster, and check the logs for that warning after adding a key. See Secrets.
Adding an existing key:
{
"operation": "add_ssh_key",
"name": "my-key",
"key": "-----BEGIN OPENSSH PRIVATE KEY-----\n...\n-----END OPENSSH PRIVATE KEY-----\n",
"host": "my-key.github.com",
"hostname": "github.com"
}
Server-side key generation (generate)
Added in: v5.2.4
With generate: true, Harper mints an ed25519 keypair on the node handling the request and returns only the public half. The private key is created inside the cluster and never travels from a client, so it can't be captured in a shell history, CI log, or request body on the way in:
{
"operation": "add_ssh_key",
"name": "my-key",
"generate": true,
"host": "my-key.github.com",
"hostname": "github.com"
}
Response:
{
"message": "Added ssh key: my-key",
"public_key": "ssh-ed25519 AAAAC3Nza... harper:my-key"
}
Register that public_key with your git host (e.g. as a GitHub deploy key) to authorize the deploy. The generated key is commented harper:<name> so it's identifiable in the host's key list.
key and generate are mutually exclusive — sending both is rejected. Generation happens in-process, so it requires no ssh-keygen binary on the host and the minted private key is never written to a temporary file on its way into storage.
public_key is returned only on the generating call — that response is the one time the public half is handed back. Harper stores the private key (sealed, subject to the custody caveat above) and the host config; it does not retain the public key for later retrieval, and update_ssh_key requires a key you supply (it can't mint one). So capture public_key from this response — if you lose it, delete_ssh_key then add_ssh_key with generate: true again to mint a fresh pair, and re-register the new public key with your git host.
Secrets
Operations for managing the encrypted secrets store (system.hdb_secret). All secret operations are super_user only. Values are never returned or logged by any of these operations.
Detailed documentation: Secrets
Prefer a UI? Harper Studio provides a graphical interface for creating, granting, and rotating secrets — it drives these operations for you, so you don't have to hand-craft the request bodies below.
| Operation | Description | Role Required |
|---|---|---|
set_secret | Creates or updates a secret and chooses its delivery tier | super_user |
grant_secret | Adds a component to a scoped secret's grants (idempotent) | super_user |
revoke_secret | Removes a component from a scoped secret's grants (idempotent) | super_user |
list_secrets | Lists secret metadata — never envelopes or values | super_user |
delete_secret | Deletes a secret row | super_user |
get_secrets_public_key | Returns the cluster public key for client-side encryption | super_user |
set_secret
Creates or updates a secret. Supply exactly one of value (plaintext, encrypted on ingest — requires custody on this node) or envelope (an enc:v1: ciphertext produced client-side against get_secrets_public_key). The delivery tier is processEnv: true or grants — the two are mutually exclusive. On update, tier and metadata default to the stored row, so a value rotation preserves the tier without re-specifying it.
| Parameter | Type | Description |
|---|---|---|
name | string | Secret name (word characters, dots, dashes). Required. |
value | string | Plaintext value; encrypted immediately, then discarded. Requires custody. |
envelope | string | enc:v1: ciphertext (alternative to value). |
processEnv | boolean | true delivers the secret via process.env (global tier). |
grants | string[] | Components allowed to read the secret via the secrets accessor (scoped tier). |
metadata | object | Optional free-form label object (not a payload store). |
{
"operation": "set_secret",
"name": "STRIPE_KEY",
"value": "sk_live_...",
"grants": ["payments-service"]
}
Response:
{ "name": "STRIPE_KEY", "kid": "<hex fingerprint>", "created": true }
grant_secret / revoke_secret
Add or remove a component from a scoped secret's grants list. Both are idempotent. A processEnv (global) secret cannot be granted — convert it with set_secret processEnv: false first.
{ "operation": "grant_secret", "name": "STRIPE_KEY", "component": "payments-service" }
Response includes the updated grants array and a changed flag (false when the call was a no-op).
list_secrets
Returns metadata for every secret — never envelopes or values. Each entry includes name, kid, grants, processEnv, metadata, unverified, updated_by, timestamps, and kid_matches_custody (so a stale row on a cloned/rekeyed node is immediately visible). The response also carries the node's custody_fingerprint (null when no custody is held).
{ "operation": "list_secrets" }
Response:
{
"secrets": [
{
"name": "STRIPE_KEY",
"kid": "a1b2c3d4...",
"grants": ["payments-service"],
"processEnv": false,
"metadata": {},
"unverified": false,
"updated_by": "admin",
"__createdtime__": 1700000000000,
"__updatedtime__": 1700000000000,
"kid_matches_custody": true
}
],
"custody_fingerprint": "a1b2c3d4..."
}
delete_secret
Removes a secret row by name. Not cryptographic erasure — audit/transaction logs and backups retain the encrypted envelope.
{ "operation": "delete_secret", "name": "STRIPE_KEY" }
get_secrets_public_key
Returns the cluster secrets public key for client-side envelope encryption. Requires custody on the node.
{ "operation": "get_secrets_public_key" }
Response:
{ "public_key": "-----BEGIN PUBLIC KEY-----\n...", "fingerprint": "<hex sha256>" }
Replication & Clustering
Operations for configuring and managing Harper cluster replication.
Detailed documentation: Replication & Clustering
| Operation | Description | Role Required |
|---|---|---|
add_node | Adds a Harper instance to the cluster | super_user |
update_node | Modifies an existing node's subscriptions | super_user |
remove_node | Removes a node from the cluster | super_user |
cluster_status | Returns current cluster connection status | super_user |
configure_cluster | Bulk-creates/resets cluster subscriptions across multiple nodes | super_user |
cluster_set_routes | Adds routes to the replication routes config (PATCH/upsert) | super_user |
cluster_get_routes | Returns the current replication routes config | super_user |
cluster_delete_routes | Removes routes from the replication routes config | super_user |
add_node
Adds a remote Harper node to the cluster. If subscriptions are not provided, a fully replicating cluster is created. Optional fields: verify_tls, authorization, retain_authorization, revoked_certificates, shard.
{
"operation": "add_node",
"hostname": "server-two",
"verify_tls": false,
"authorization": { "username": "admin", "password": "password" }
}
cluster_status
Returns connection state for all cluster nodes, including per-database socket status and replication timing statistics (lastCommitConfirmed, lastReceivedRemoteTime, lastReceivedLocalTime).
{ "operation": "cluster_status" }
configure_cluster
Resets and replaces the entire clustering configuration. Each entry follows the add_node schema.
{
"operation": "configure_cluster",
"connections": [
{
"hostname": "server-two",
"subscriptions": [{ "database": "dev", "table": "dog", "subscribe": true, "publish": true }]
}
]
}
Configuration
Operations for reading and updating Harper configuration.
Detailed documentation: Configuration Overview
| Operation | Description | Role Required |
|---|---|---|
set_configuration | Modifies Harper configuration file parameters (requires restart) | super_user |
get_configuration | Returns the current Harper configuration | super_user |
set_configuration
Updates configuration parameters in harper-config.yaml. A restart (restart or restart_service) is required for changes to take effect.
Supports "replicated": true Added in: v5.2.0 to apply the same change to all cluster nodes in one call; per-node outcomes are returned in the response's replicated array. Only send cluster-appropriate parameters when replicating — node-local parameters (ports, node.hostname, file paths, TLS material, replication.hostname/url/routes) would overwrite every peer's local values. To apply the change cluster-wide, follow with restart_service using "replicated": true (which restarts nodes one at a time). See Configuration Operations for details.
{
"operation": "set_configuration",
"logging_level": "trace",
"replicated": true
}
get_configuration
Returns the full current configuration object.
{ "operation": "get_configuration" }
Web Application Firewall
Added in: v5.2.0Operations for managing Web Application Firewall rules and cluster-wide enforcement controls.
Detailed documentation: WAF Operations and Rule Schema
| Operation | Description | Role Required |
|---|---|---|
add_waf_rule | Creates a validated WAF rule | super_user |
alter_waf_rule | Patches and revalidates an existing WAF rule | super_user |
drop_waf_rule | Deletes a WAF rule | super_user |
list_waf_rules | Returns all WAF rules | super_user |
set_waf_mode | Sets the replicated mode and/or scoring threshold | super_user |
System
Operations for restarting Harper and managing system state.
| Operation | Description | Role Required |
|---|---|---|
restart | Restarts the Harper instance | super_user |
restart_service | Restarts a specific Harper service | super_user |
system_information | Returns detailed host system metrics | super_user |
set_status | Sets an application-specific status value (in-memory) | super_user |
get_status | Returns a previously set status value | super_user |
clear_status | Removes a status entry | super_user |
restart
Restarts all Harper processes. May take up to 60 seconds.
{ "operation": "restart" }
restart_service
Restarts a specific service. service must be one of: http, http_workers, custom_functions, harperdb (all currently restart the HTTP workers). Supports "replicated": true for a rolling cluster restart.
{ "operation": "restart_service", "service": "http_workers" }
system_information
Returns system metrics including CPU, memory, disk, network, and Harper process info. Optionally filter by attributes array (e.g., ["cpu", "memory", "replication"]).
{ "operation": "system_information" }
set_status / get_status / clear_status
Manage in-memory application status values. Status types: primary, maintenance, availability (availability only accepts 'Available' or 'Unavailable'). Status is not persisted across restarts.
{ "operation": "set_status", "id": "primary", "status": "active" }
Backup & Restore
Operations for backing up and restoring databases. Managed backups Added in: v5.2.0 require the RocksDB storage engine; get_backup works with both RocksDB and LMDB.
Detailed documentation: Backup Operations
| Operation | Description | Role Required |
|---|---|---|
create_backup | Creates a managed, incremental directory backup of a database (job) | super_user |
list_backups | Lists the managed backups for a database | super_user |
verify_backup | Verifies a managed backup's integrity (job) | super_user |
delete_backup | Deletes a single managed backup | super_user |
purge_backups | Deletes all but the newest keep_count managed backups | super_user |
restore_backup | Restores a database from a managed backup (job) | super_user |
get_backup | Streams a full snapshot of a database in the response for download | super_user |
create_backup
Creates an incremental directory backup of the database under the configured backup root. Runs as a background job that reports the new backup_id.
{ "operation": "create_backup", "database": "dev" }
list_backups
Returns the managed backups for a database, each with its backup_id, timestamp, size, and file_count.
{ "operation": "list_backups", "database": "dev" }
verify_backup
Verifies a managed backup's integrity, including checksums when verify_checksum is true (slower). Runs as a background job.
{ "operation": "verify_backup", "database": "dev", "backup_id": 1, "verify_checksum": true }
delete_backup
Deletes a single managed backup.
{ "operation": "delete_backup", "database": "dev", "backup_id": 1 }
purge_backups
Deletes all but the newest keep_count managed backups.
{ "operation": "purge_backups", "database": "dev", "keep_count": 3 }
restore_backup
Restores a database in place from a managed backup, as a background job. backup_id defaults to the latest backup. Restoring the system database, or a database a loaded component keeps open, requires the server to be stopped — see when can a database be restored?
{ "operation": "restore_backup", "database": "dev", "backup_id": 1 }
get_backup
Streams a full snapshot of the specified database in the HTTP response for download. For RocksDB Changed in: v5.2.0, a tar archive of the current state (including file-backed blobs unless exclude_blobs is set), gzipped by default; for LMDB, the .mdb file.
{ "operation": "get_backup", "database": "dev" }
Jobs
Operations for querying background job status.
Detailed documentation: Database Jobs
| Operation | Description | Role Required |
|---|---|---|
get_job | Returns status and results for a specific job ID | any |
search_jobs_by_start_date | Returns jobs within a specified time window | super_user |
get_job
Returns job status (COMPLETE, IN_PROGRESS, ERROR), timing, and result message for the specified job ID. Bulk import/export operations return a job ID on initiation.
{ "operation": "get_job", "id": "4a982782-929a-4507-8794-26dae1132def" }
search_jobs_by_start_date
Returns all jobs started within the specified datetime range.
{
"operation": "search_jobs_by_start_date",
"from_date": "2021-01-25T22:05:27.464+0000",
"to_date": "2021-01-25T23:05:27.464+0000"
}
Logs
Operations for reading Harper logs.
Detailed documentation: Logging Operations
| Operation | Description | Role Required |
|---|---|---|
read_log | Returns entries from the primary hdb.log | super_user |
read_transaction_log | Returns transaction history for a table | super_user |
delete_transaction_logs_before | Deletes transaction log entries older than a timestamp | super_user |
read_audit_log | Returns verbose transaction history for a table, including original record values (requires transaction logging enabled) | super_user |
delete_audit_logs_before | Deletes transaction log entries older than a timestamp (deprecated alias of delete_transaction_logs_before) | super_user |
read_log
Returns entries from hdb.log. Filter by level (notify, error, warn, info, debug, trace), date range (from, until), and text filter.
{
"operation": "read_log",
"start": 0,
"limit": 100,
"level": "error"
}
read_transaction_log
Returns transaction history for a specific table. Optionally filter by from/to (millisecond epoch) and limit.
{
"operation": "read_transaction_log",
"schema": "dev",
"table": "dog",
"limit": 10
}
read_audit_log
Returns verbose transaction history including original record state. Requires transaction logging (logging.auditLog: true) in configuration. Filter by search_type: hash_value, timestamp, or username.
{
"operation": "read_audit_log",
"schema": "dev",
"table": "dog",
"search_type": "username",
"search_values": ["admin"]
}
Certificate Management
Operations for managing TLS certificates in the hdb_certificate system table.
Detailed documentation: Certificate Management
| Operation | Description | Role Required |
|---|---|---|
add_certificate | Adds or updates a certificate | super_user |
remove_certificate | Removes a certificate and its private key file | super_user |
list_certificates | Lists all certificates | super_user |
add_certificate
Adds a certificate to hdb_certificate. If a private_key is provided, it is written to <rootPath>/keys/ (not stored in the table). If no private key is provided, the operation searches for a matching one on disk.
{
"operation": "add_certificate",
"name": "my-cert",
"certificate": "-----BEGIN CERTIFICATE-----...",
"is_authority": false,
"private_key": "-----BEGIN RSA PRIVATE KEY-----..."
}
Analytics
Operations for querying analytics metrics.
Detailed documentation: Analytics Operations
| Operation | Description | Role Required |
|---|---|---|
get_analytics | Retrieves analytics data for a specified metric | any |
list_metrics | Lists available analytics metrics | any |
describe_metric | Returns the schema of a specific metric | any |
get_analytics
Retrieves analytics data. Supports start_time/end_time (Unix ms), get_attributes, and conditions (same format as search_by_conditions).
{
"operation": "get_analytics",
"metric": "resource-usage",
"start_time": 1769198332754,
"end_time": 1769198532754
}
list_metrics
Returns available metric names. Filter by metric_types: custom, builtin (default: builtin).
{ "operation": "list_metrics" }
Registration & Licensing
Operations for license management.
| Operation | Description | Role Required |
|---|---|---|
registration_info | Returns registration and version information | any |
install_usage_license | Installs a Harper usage license block | super_user |
get_usage_licenses | Returns all usage licenses with consumption counts | super_user |
get_fingerprint | (Deprecated) Returns the machine fingerprint | super_user |
set_license | (Deprecated) Sets a license key | super_user |
registration_info
Returns the instance registration status, version, RAM allocation, and license expiration.
{ "operation": "registration_info" }
install_usage_license
Installs a usage license block. A license is a JWT-like structure (header.payload.signature) signed by Harper. Multiple blocks may be installed; earliest blocks are consumed first.
{
"operation": "install_usage_license",
"license": "abc...0123.abc...0123.abc...0123"
}
get_usage_licenses
Returns all usage licenses (including expired/exhausted) with current consumption counts. Optionally filter by region.
{ "operation": "get_usage_licenses" }
Deprecated Operations
The following operations are deprecated and should not be used in new code.
Custom Functions (Deprecated)
Custom Functions were the precursor to the Component architecture introduced in v4.2.0. These operations are preserved for backward compatibility.
Deprecated in: v4.2.0 (moved to legacy in v4.7+)
For modern equivalents, see Components Overview.
| Operation | Description |
|---|---|
custom_functions_status | Returns Custom Functions server status |
get_custom_functions | Lists all Custom Function projects |
get_custom_function | Returns a Custom Function file's content |
set_custom_function | Creates or updates a Custom Function file |
drop_custom_function | Deletes a Custom Function file |
add_custom_function_project | Creates a new Custom Function project |
drop_custom_function_project | Deletes a Custom Function project |
package_custom_function_project | Packages a Custom Function project as base64 tar |
deploy_custom_function_project | Deploys a packaged Custom Function project |
Other Deprecated Operations
| Operation | Replaced By |
|---|---|
install_node_modules | Handled automatically by deploy_component and restart |
get_fingerprint | Use registration_info |
set_license | Use install_usage_license |
search_by_hash | Use search_by_id |
search_attribute | Use attribute field in search_by_value / search_by_conditions |
search_value | Use value field in search_by_value / search_by_conditions |
search_type | Use comparator field in search_by_conditions |