Redis HTTP API
Run Redis commands in a disk namespace. Redis keys share the disk’s storage and lifecycle and use a separate keyspace from the typed KV API. Start with SET and GET.
Endpoint
Section titled “Endpoint”The base URL is https://api.wabe.sh/v1/disks/DISK/redis/NAMESPACE.
| Method | Suffix | Request |
|---|---|---|
| POST or PUT | Empty | One JSON command array. |
| POST or PUT | /pipeline |
An array of command arrays, executed in order. Other clients can interleave. |
| POST or PUT | /multi-exec |
An array of command arrays, executed as one isolated transaction. |
| GET, POST or PUT | /COMMAND/ARG/... |
URL-encoded command arguments. POST/PUT appends a nonempty raw body as the last argument, followed by query options. |
Parameters
Section titled “Parameters”disk and namespace use 1-128 ASCII letters, digits, underscores or hyphens. The same server Bearer key authenticates every namespace. Keys, hash fields, set members and sorted-set members are byte strings up to 16 KiB. Individual string values, hash values and list elements are at most 1 MiB.
A JSON command array contains a command name followed by string, number or boolean arguments. The SDK serializes objects to JSON strings before sending them.
Requests and encoded staged mutations are bounded at 8 MiB. Replies are bounded at 8 MiB before JSON/base64 expansion. Large multi-command requests can hit the mutation budget before the transport limit. Collections store elements individually; operations that modify many elements can hit this budget.
Request
Section titled “Request”curl --fail --json '["SET","processed","0"]' \ -H "Authorization: Bearer YOUR_PROJECT_API_KEY" \ "https://api.wabe.sh/v1/disks/demo/redis/app"curl --fail --json '["INCR","processed"]' \ -H "Authorization: Bearer YOUR_PROJECT_API_KEY" \ "https://api.wabe.sh/v1/disks/demo/redis/app"A transaction can read its preceding writes:
curl --fail --json '[["SET","attempts","0"],["INCR","attempts"],["GET","attempts"]]' \ -H "Authorization: Bearer YOUR_PROJECT_API_KEY" \ "https://api.wabe.sh/v1/disks/demo/redis/app/multi-exec"Commands that can modify data execute sequentially within each Redis namespace. A multi-exec request containing writes holds that namespace’s write lock for its whole transaction. Read-only commands use the existing storage snapshots and can run while writes are queued or executing. Other namespaces and disks have independent write locks.
The first SCAN or DBSIZE may initialize stored metadata and joins the write queue for that initialization. Expiration GC uses the same lock when deleting a key. The lock is released after publication in memory; waiting for remote durability and sending the response happen afterward. Each request keeps its configured acknowledgement guarantees. Waiting requests retain their bounded request buffers; there is no aggregate queue memory limit.
Response
Section titled “Response”Single commands return {"result":...}. A missing GET returns {"result":null}. Pipeline and multi return one envelope per command, for example:
[{"result":"OK"},{"result":1},{"result":"1"}]Command names and option names are case-insensitive. JSON preserves strings as strings; the JavaScript SDK can deserialize them into numbers or objects.
Upstash-Encoding: base64 encodes reply strings and array strings, except status OK. Error messages remain plain text. Default JSON replaces invalid UTF-8 with replacement characters. Upstash-Response-Format: resp2 returns binary RESP2 for single commands and pipelines. It cannot be combined with base64 or used with multi-exec.
Supported commands
Section titled “Supported commands”| Family | Commands and options |
|---|---|
| Connection | PING, ECHO |
| Strings | GET, GETDEL, GETSET, GETEX, SET, SETNX, SETEX, PSETEX, MGET, MSET, MSETNX, APPEND, STRLEN, GETRANGE, SETRANGE |
| Conditional writes | SET NX, XX, IFEQ, IFNE, GET; DELEX with optional IFEQ or IFNE |
| Counters | INCR, DECR, INCRBY, DECRBY; signed int64 arithmetic with overflow errors |
| Keys | DEL, UNLINK, EXISTS, TYPE, SCAN with MATCH, COUNT, TYPE; DBSIZE; TIME |
| Expiration | SET EX/PX/EXAT/PXAT/KEEPTTL; GETEX EX/PX/EXAT/PXAT/PERSIST; EXPIRE, PEXPIRE, EXPIREAT, PEXPIREAT with NX, XX, GT or LT conditions; TTL, PTTL, PERSIST, EXPIRETIME, PEXPIRETIME |
| Lists | LPUSH, RPUSH, LPUSHX, RPUSHX, LPOP, RPOP, LLEN, LRANGE, LINDEX, LSET, LTRIM, LREM, LMOVE, RPOPLPUSH |
| Hashes | HSET, HGET, HMGET, HGETALL, HDEL, HEXISTS, HLEN, HINCRBY, HSCAN with MATCH, COUNT, NOVALUES |
| Sets | SADD, SREM, SISMEMBER, SMISMEMBER, SCARD, SMEMBERS, SPOP with optional count, SSCAN with MATCH, COUNT |
| Sorted sets | ZADD with NX, XX, GT, LT, CH, INCR; ZREM, ZRANGE with BYSCORE, BYLEX, REV, LIMIT, WITHSCORES; ZRANGEBYSCORE with LIMIT, WITHSCORES; ZREMRANGEBYSCORE, ZSCORE, ZCARD, ZCOUNT, ZINCRBY, ZPOPMIN with optional count |
Expiration conditions can combine XX with GT or LT. NX conflicts with XX, GT and LT; GT conflicts with LT. When combining a SET IFEQ or IFNE comparison with NX or XX, place the comparison first, for example SET key next IFEQ previous XX.
Expiration is checked during operations using server time. TTL/PTTL return -2 for a missing or expired key and -1 for a persistent key. Mutations such as INCR and list push preserve existing expiration; SET normally replaces it.
EXPIRETIME and PEXPIRETIME return the absolute deadline in seconds or milliseconds, or the same -2/-1 sentinels. TIME returns two strings: Unix seconds and microseconds within that second. It uses server time.
DBSIZE returns the number of stored Redis keys in this namespace, including keys whose TTL has expired until GC removes their records. A hash, list, set or sorted set counts as one key. Reads and SCAN hide expired keys immediately; DBSIZE can therefore exceed the number of keys returned by a complete scan. Replacing an expired record keeps the count unchanged. Deleting a live key or its final collection element decrements the count in the same transaction. Expiration commands that immediately delete a live key, such as EXPIRE key 0, also decrement it immediately.
Hash, set and sorted-set updates preserve the key’s expiration. Removing the final field or member deletes the key. HINCRBY uses signed int64 arithmetic. Sorted-set scores use IEEE 754 doubles, accept infinities and reject NaN. Equal scores sort members by their unsigned bytes; REV reverses that order too. Use BYLEX with members that have equal scores, as required by Redis. LIMIT requires BYSCORE or BYLEX, and BYLEX cannot combine with WITHSCORES.
Read collections and scan keys
Section titled “Read collections and scan keys”curl --fail --json '["HSET","task:1","title","Check storage","attempts","0"]' \ -H "Authorization: Bearer YOUR_PROJECT_API_KEY" \ "https://api.wabe.sh/v1/disks/demo/redis/app"curl --fail --json '["HGETALL","task:1"]' \ -H "Authorization: Bearer YOUR_PROJECT_API_KEY" \ "https://api.wabe.sh/v1/disks/demo/redis/app"curl --fail --json '["SCAN","0","MATCH","task:*","TYPE","hash","COUNT","100"]' \ -H "Authorization: Bearer YOUR_PROJECT_API_KEY" \ "https://api.wabe.sh/v1/disks/demo/redis/app"The HTTP HGETALL result is a flat field/value array in unspecified order. The SDK converts it to an object. SMEMBERS and scan results also have unspecified order. Sorted-set replies with scores contain alternating member and score strings.
SCAN, HSCAN and SSCAN return [cursor, items]. Start with the string "0" and pass each returned cursor unchanged until it is "0" again. Cursors are opaque unsigned decimal strings; converting them to JavaScript numbers can lose precision. A page can be empty with a nonzero cursor. COUNT is a work hint; pages also respect the reply budget. HSCAN normally returns field/value pairs; NOVALUES returns fields only. Patterns use the 16 KiB key limit and support binary Redis globs: *, ?, ranges, negated classes and backslash escapes.
A complete scan returns every element that remains present throughout the iteration. Concurrent changes may appear or disappear; scans are not snapshots across requests. Page boundaries and cursor values can differ from Redis. The first SCAN on a disk written by an earlier version builds its index in bounded batches; subsequent scans resume at the indexed cursor.
DBSIZE uses point lookups after initialization: a readiness check and a counter read in the command’s snapshot. An existing namespace without a counter initializes it with one streaming pass over its stored key records on the first DBSIZE or command that creates or deletes a key. The initial pass is linear and uses bounded memory. New namespaces initialize the counter before creating their first key. Creating and deleting keys update the shared namespace counter atomically under the write lock. Storage conflict checks and bounded retries remain enabled.
HGETALL and SMEMBERS must fit one reply. Use HSCAN or SSCAN for larger collections. ZCOUNT over a partial score range, rank-based ZRANGE with a large offset from both ends, and range deletion perform linear work over the visited records while keeping memory bounded. ZCOUNT key -inf +inf uses the stored cardinality; rank ranges start from the nearer end. These operations do not have Redis’s in-memory tree performance.
Invalid request JSON, command names or arities reject multi-exec before execution. A runtime error such as INCR against a list becomes that command’s error reply; successful commands still commit. Storage failures and resource-limit failures can reject the transaction. Internal transaction conflicts are retried with bounded backoff.
Blocking commands, Lua, Streams, Pub/Sub, WATCH, ZSCAN and a TCP Redis listener are unavailable. Compatibility covers the documented commands/options and wabe Disk limits. It does not imply support for every Redis-dependent library.
Persistence and cleanup
Section titled “Persistence and cleanup”Buffered acknowledgements confirm RAM publication. Remote mode waits for background or explicit persistence without forcing a flush for each command. A later script error does not undo completed commands. Disconnects can leave a mutation’s acknowledgement outcome unknown. See durability.
DEL, replacement and expiration make collection contents inaccessible immediately. GC reclaims expired Redis roots and retired collection elements and indexes in bounded batches. Redis changes do not produce KV notification records.
Errors
Section titled “Errors”Command errors use HTTP 400 and {"error":"..."}. A pipeline/multi with per-command runtime errors uses HTTP 200 and includes error envelopes. HTTP body/aggregate response limits use 413. Storage failures use 500. Authentication follows the server’s shared 401 response. Empty JSON batch arrays return an empty response array.