Developer documentation

ShareAnyData stores your configuration and feature flags as versioned JSON and serves the published version from Cloudflare's edge. There are two surfaces: a Read API your apps call to fetch live config, and an Authoring API behind the dashboard for creating and publishing it.

Base URL for the API: https://api.shareanydata.com

Concepts

Quickstart

  1. Create a free account and a workspace (you get one free workspace + one published config).
  2. Create a config, edit its JSON, and click Publish.
  3. Create a read key under the workspace's API keys.
  4. Fetch it from anywhere:
curl -H "Authorization: Bearer sad_read_•••" \
  https://api.shareanydata.com/v1/acme/prod/feature-flags

# → 200
# {"checkout_v2": true, "max_items": 25}

API keys

Create keys in the dashboard under a workspace → API keys. Present a read key one of two ways:

Authorization: Bearer sad_read_•••        # preferred
?key=sad_read_•••                          # for header-less clients (e.g. <img>/<script>)

Read keys are read-only and safe to ship in client apps. You can scope a read key to a single environment and revoke any key instantly. Never ship a server key.

Read API — get a config

GET /v1/{projectKey}/{env}/{configKey}

Returns the live published JSON for that config, or 404 not_published if it has never been published.

GET /v1/acme/prod/feature-flags
Authorization: Bearer sad_read_•••

200 OK
ETag: "v_8x2k…"
Cache-Control: public, max-age=60, stale-while-revalidate=86400
Content-Type: application/json

{ "checkout_v2": true, "max_items": 25 }

HEAD /v1/{projectKey}/{env}/{configKey} returns the headers (including the ETag) with no body — a cheap way to poll for changes.

Read API — get all configs in an environment

GET /v1/{projectKey}/{env} returns every live config in one request — handy at app start.

GET /v1/acme/prod
Authorization: Bearer sad_read_•••

200 OK
{ "configs": { "feature-flags": { … }, "pricing": { … } } }

Caching & ETags

The ETag is the published version's id, so it changes only when you publish a new version. Send it back with If-None-Match to get a tiny 304 instead of the full body:

GET /v1/acme/prod/feature-flags
If-None-Match: "v_8x2k…"

304 Not Modified            # no body — your client keeps its cached value

Responses are cached at Cloudflare's edge (max-age=60, stale-while-revalidate=86400). Publishing a new version refreshes the edge cache so reads pick it up quickly. The SDKs handle ETag caching and conditional requests for you.

SDK — Web / JavaScript / TypeScript

npm i @shareanydata/web
import { createClient } from "@shareanydata/web";

const sad = createClient({
  sdkKey: "sad_read_•••",
  projectKey: "acme",
  env: "prod",
  pollIntervalMs: 30000,        // optional: detect new publishes
});

const flags = await sad.get("feature-flags");
if (flags.checkout_v2) renderNewCheckout();

sad.on("feature-flags", (next) => applyFlags(next));  // fires on change
const all = await sad.getAll();                        // every config in the env

Isomorphic (browser + Node 18+). Caches by ETag, sends conditional requests, serves the last value when offline, and zero dependencies.

SDK — iOS / Swift

// Swift Package Manager
.package(url: "https://github.com/shareanydata/sdk-ios", from: "0.1.0")
import ShareAnyData

let sad = ShareAnyData(sdkKey: "sad_read_•••", projectKey: "acme", env: "prod",
                       options: .init(pollInterval: 30))

struct Flags: Decodable { let checkout_v2: Bool; let max_items: Int }
let flags: Flags = try await sad.get("feature-flags")
sad.observe("feature-flags") { (f: Flags) in apply(f) }

SDK — Android / Kotlin

// build.gradle.kts
implementation("com.shareanydata:sdk:0.1.0")
val sad = ShareAnyData(context, sdkKey = "sad_read_•••",
                       projectKey = "acme", env = "prod", pollIntervalMs = 30000)

val flags = sad.get("feature-flags")          // suspend → JSONObject
if (flags.getBoolean("checkout_v2")) showNewCheckout()
sad.observe("feature-flags") { next -> applyFlags(next) }

Authoring API — overview & auth

The dashboard talks to the authoring API on the same origin under /api/…. Requests are authenticated with the bearer token you receive when you sign in (Google or Apple), and gated by your plan. Use it to script project setup or CI publishing.

Authorization: Bearer <your session JWT>
Content-Type: application/json

Authoring API — endpoints

GET/api/auth/meCurrent user + entitlement.
GET/api/projectsList your workspaces.
POST/api/projectsCreate a workspace { name } (seeds template/dev/stage/cert/prod).
GET/api/projects/:keyProject + environments.
POST/api/projects/:key/envsAdd an environment (max 6).
POST/api/projects/:key/envs/:env/configsCreate a config { configKey, content? }.
POST…/configs/:cfg/versionsSave a new version { content }.
GET…/configs/:cfg/diffMissing/extra keys vs the linked template.
POST…/configs/:cfg/promotePromote to another env { targetEnv }.
POST…/configs/:cfg/publishPublish the head (or { versionId }).
POST…/configs/:cfg/unpublishTake a config offline.
POST/api/projects/:key/keysCreate a key { kind: "read"|"server", label?, envScope? }.
GET/api/projects/:key/exportExport the whole project as JSON.

Errors

401missing_read_key / unauthenticated — no or invalid credential.
402quota_exceeded / project_limit — plan limit reached; upgrade.
403Key doesn't match the project, or is out of its environment scope.
404not_published / *_not_found — nothing live at that path.

All error bodies are JSON: { "error": "…" } (plus context fields where useful).

Start free