Documentation

HTTP data plane

Advanced reference. The normal integration — for every Redis client — is the one-line Redis connection string. This page documents the JSON-over-HTTPS API that sits underneath it: the layer the gateway translates every Redis command into, and the endpoint list exposed through openapi.json. Reach for it only when you are building non-Redis tooling (HTTP probes, control scripts, restricted-egress callers).

Advanced reference JSON envelope Bearer rk_ keys

Base path

Every data call lives under one base path:

Service base path (not a client connection string)
https://cacheify.bot-keep.xyz/api/data/{dbId}

All requests take Authorization: Bearer <rk_…> — the database's single active API key. Redis array replies come back as JSON arrays; Redis nil is null; a missing or expired key is HTTP 404.

Endpoints

MethodPathPurpose
POST/api/data/{dbId}/commandRun one Redis command {"command","args"}
POST/api/data/{dbId}/pipelineAtomic batch of 1-50 commands [{"command","args"}]
GET/api/data/{dbId}/keys?pattern=&cursor=Browse keys (cursor paging)
GET/api/data/{dbId}/keys/{key}Key detail: value + ttlMs (404 = absent or expired)
PUT/api/data/{dbId}/strings/{key}Save a string {"value","expiresInMs"?}
DELETE/api/data/{dbId}/keys/{key}Delete a key
POST/api/data/{dbId}/keys/{key}/expireRe-arm a TTL {"expiresInMs"}
POST/api/data/{dbId}/rate-limitRate-limit probe for client feedback

Full machine-readable contract: GET /api/openapi.json.

Cookbook: store, then read

The two calls most auth flows need — a 5-minute TTL value and its read-back:

cURL
curl -X PUT "https://cacheify.bot-keep.xyz/api/data/$DB_ID/strings/session:9942" \
  -H "Authorization: Bearer $RK_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"value":"active","expiresInMs":300000}'
Python (requests)
import os, requests

base = os.environ["CACHEIFY_BASE_URL"]
auth = {"Authorization": "Bearer " + os.environ["CACHEIFY_API_KEY"]}

# save with a 5-minute TTL
requests.put(f"{base}/api/data/{os.environ['CACHEIFY_DB_ID']}/strings/session:9942",
             headers=auth, json={"value": "active", "expiresInMs": 300000})

# read back: value + remaining TTL in one call
detail = requests.get(f"{base}/api/data/{os.environ['CACHEIFY_DB_ID']}/keys/session:9942",
                      headers=auth).json()
value, ttl_ms = detail["data"]["key"]["value"], detail["data"]["key"]["ttlMs"]
Node.js (native fetch)
const base = process.env.CACHEIFY_BASE_URL;
const auth = { Authorization: `Bearer ${process.env.CACHEIFY_API_KEY}` };

// save with a 5-minute TTL
await fetch(`${base}/api/data/${process.env.CACHEIFY_DB_ID}/strings/session:9942`, {
  method: 'PUT',
  headers: { ...auth, 'Content-Type': 'application/json' },
  body: JSON.stringify({ value: 'active', expiresInMs: 300000 }),
});

// read back: 404 means the key expired or never existed
const { key } = await (await fetch(
  `${base}/api/data/${process.env.CACHEIFY_DB_ID}/keys/session:9942`,
  { headers: auth },
)).json();  // key.value, key.ttlMs

Pipeline instead of round-trips

Send a batch of 1-50 commands that execute in order with one HTTP round-trip; each reply comes back in its own element:

3 chained commands, one request
curl -X POST https://cacheify.bot-keep.xyz/api/data/$DB_ID/pipeline \
  -H "Authorization: Bearer $RK_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"commands":[
        {"command":"HSET","args":["cart:7719","sku-1","2"]},
        {"command":"HSET","args":["cart:7719","sku-4","1"]},
        {"command":"HGETALL","args":["cart:7719"]}]}'

Per-database concurrency is capped server-side (MAX_INFLIGHT_PER_DB): a saturated database answers 429 + Retry-After immediately instead of holding your socket.

Spring Boot without Redis deps

Spring's RedisTemplate speaks RESP over TCP — for that path use the gateway connection string. For serverless or restricted-egress deployments, the HTTP bridge below keeps the same interface so your service layer never learns the difference:

application.properties
# application.properties (values come from the environment, never hardcoded)
cacheify.base-url=${CACHEIFY_BASE_URL:https://cacheify.bot-keep.xyz}
cacheify.database-id=${CACHEIFY_DB_ID:}
cacheify.api-key=${CACHEIFY_API_KEY:}
HttpOtpStore.java (bridge)
// Spring HTTP bridge: same OtpStore interface, Cacheify over REST instead
// of the Redis protocol. For serverless or locked-down-egress callers.
// storeOtpHash  -> PUT    /api/data/{dbId}/strings/{key}  (expiresInMs)
// getOtpHash    -> GET    /api/data/{dbId}/keys/{key}     (value + ttlMs)
// deleteOtpHash -> DELETE /api/data/{dbId}/keys/{key}
@Repository
public class HttpOtpStore implements OtpStore {

  private static final Duration TTL = Duration.ofMinutes(5);
  private static final String PREFIX = "myapp:otp:";

  private final RestTemplate http;
  private final String baseUrl, dbId, apiKey;

  public HttpOtpStore(RestTemplate cacheifyRestTemplate,
                      @Value("${cacheify.base-url}") String baseUrl,
                      @Value("${cacheify.database-id}") String dbId,
                      @Value("${cacheify.api-key}") String apiKey) {
    this.http = cacheifyRestTemplate; this.baseUrl = baseUrl;
    this.dbId = dbId; this.apiKey = apiKey;
  }

  public void storeOtpHash(String email, String otpHash) {
    http.exchange(url("strings", email), HttpMethod.PUT,
        json(Map.of("value", otpHash, "expiresInMs", TTL.toMillis())), String.class);
  }

  public Optional<String> getOtpHash(String email) {
    try {
      Map<?, ?> env = http.getForObject(url("keys", email), Map.class);
      Map<?, ?> key = (Map<?, ?>) ((Map<?, ?>) env.get("data")).get("key");
      return Optional.ofNullable((String) key.get("value"));
    } catch (HttpStatusCodeException gone) {
      return Optional.empty();   // 404: never issued, consumed, or expired
    }
  }

  public void deleteOtpHash(String email) {
    http.exchange(url("keys", email), HttpMethod.DELETE, json(null), String.class);
  }

  private String url(String resource, String email) {
    return baseUrl + "/api/data/" + dbId + "/" + resource + "/"
        + URLEncoder.encode(PREFIX + email.toLowerCase(), StandardCharsets.UTF_8);
  }

  private static HttpEntity<Map<String, Object>> json(Map<String, Object> body) {
    HttpHeaders headers = new HttpHeaders();
    headers.set("Authorization", "Bearer " + apiKey);
    headers.set("Content-Type", "application/json");
    return new HttpEntity<>(body, headers);
  }
}
  • 404 maps to Optional.empty() — identical to a Redis nil read.
  • URL-encode key names (URLEncoder covers : and @ in e-mails).
  • Wire the key through properties sourced from env vars; never hardcode it.