Quickstart: from sign-up to your first answer

Squiddy answers one question for the apps you have already shipped: what configuration should I be using right now? This page takes you from having no account at all to a real answer from the data plane — five steps, one curl, no SDK.

These are the same steps the product walks you through once you have signed up, in the same order: the page you are reading and the guide inside the dashboard are generated from one declaration, so reading first and signing up first lead to the same place.

What you need

The values you supply

Every command below uses these shell variables and nothing else, and each one is set by a command on this page.

VariableWhat to put in it
SQUIDDY_HOSTThe origin your Squiddy is served on, with no trailing slash: the scheme and host in your browser's address bar while you are signed in to the dashboard (http://localhost:7071 for a local run).
SQUIDDY_API_KEYThe API key secret from step 3. It is shown once, so it is the one value here you cannot look up again later.
SQUIDDY_APP_IDThe id of the app whose configuration you are asking for — the one you publish in step 4. Left as my-app the command still runs; step 5 says what it answers.

1. Create your account

In your browser.

Open /auth/register on the Squiddy you are signing up to and create an account with your email address. Signing up and signing in are separate doors: /auth/login asks for credentials you already have, /auth/register is where they come from.

Signing up sends you no mail: the next screen is where you ask for the confirmation message. An organization cannot be created from an address nobody has proved they own, so until yours is confirmed that screen stands in for the form — press Send the confirmation message, open the link in the message, and come back. The form will be waiting, and you will not have to sign in again.

2. Your organization's coordinates

In your browser.

Sign in and create your organization: a name, and the handle it is addressed by. A project and an environment are created with it, so your organization is addressable before you have configured anything — which is what the guide's first step is showing you.

Three coordinates identify every configuration you will ever publish:

CoordinateWhat it isWhat you start with
OrganizationYour tenant: everything below belongs to it, and nothing crosses between two of them.the handle you chose
ProjectOne product.default
EnvironmentOne deployment of that product — production, staging, whatever you keep apart.default

You will not have to type them into the call in step 4. A key belongs to exactly one environment, and an environment to exactly one project, so presenting a key tells the server all three. The coordinates start mattering when you have more than one environment and are choosing which to publish into.

3. Create your first API key

In your browser, then in your terminal.

The guide's second step mints your first key, into the environment it has just shown you. Outside the guide the same key is created from API keys in the sidebar.

The secret is shown once. Only its fingerprint is stored, so nobody — including us — can show it to you again: copy it now. If you lose it, create another key and revoke the one you lost.

Put the two values the commands below need into your shell:

export SQUIDDY_HOST=REPLACE_WITH_YOUR_SQUIDDY_ORIGIN
export SQUIDDY_API_KEY=sqd_REPLACE_WITH_THE_SECRET_YOU_JUST_COPIED

It is a credential: it belongs in an environment variable or a secret manager, never in a repository and never in a client bundle you ship.

4. Make your first request

In your browser, then in your terminal.

First, publish something for it to answer. Creating an organization gives you a project and an environment, but no configuration — so until you publish one the data plane answers not_found, correctly, because there is nothing there yet.

In the dashboard, open your environment from Projects in the sidebar. Type an app id into New app and press New, edit the body, then Save draft and Publish. The app id you chose is what the call below asks for.

Name that app and ask for its configuration:

export SQUIDDY_APP_ID=my-app

curl -sS "$SQUIDDY_HOST/squiddy.v1.ConfigService/GetRemoteConfiguration" \
  -H 'Content-Type: application/json' \
  -H "X-API-Key: $SQUIDDY_API_KEY" \
  --data-binary @- <<JSON
{
  "appId": "$SQUIDDY_APP_ID",
  "appBundleId": "com.example.app",
  "appVersion": "2026.01.01",
  "appType": "ios",
  "appMode": "release",
  "appLanguage": "en"
}
JSON

Those six fields are the request. appId names the configuration you want; the other five describe the app asking for it, and are what resolution is decided on — a rule can answer one thing to ios and another to android, one thing to release and another to debug. Those five are examples and work as they are; put your app's real values in when you wire this into it.

Keep appVersion in the YYYY.MM.DD shape: it is compared numerically, so a 1.0.0 would sort below every rule written for a real release and turn a correct call into a confusing one.

Nothing else is required — no SDK, no Authorization header, no protobuf on the wire. The service speaks Connect, so this path takes plain JSON (and gRPC, if you would rather). Every field of the request and the response is in the ConfigService reference.

5. Your first response

Nothing to do.

A published app answers with its configuration. This is the whole product: everything else in Squiddy exists to decide what goes into this payload, and for whom.

200 OK — wrapped here to be read; curl prints it on one line:

{
  "hubName": "Squiddy",
  "hubVersion": "2023.11.15",
  "configVersion": "2026.08.07",
  "serverApi": {
    "baseUrl": "https://api.example.com/v1/",
    "mode": "path",
    "apiVersion": "1.0"
  },
  "languages": {
    "defaultLang": "en",
    "langList": [{ "entries": { "en": { "items": [{ "entries": { "greeting": "Hello" } }] } } }]
  },
  "langFingerprint": "b3a85f4f…336add",
  "configFingerprint": "a36f1250…3574c1"
}
FieldWhat it is
configVersionThe version of the configuration that answered. It changes when you publish.
serverApiThe block your app reads its own backend's coordinates out of.
configFingerprintSend it back as the request's configFingerprint next time: if nothing has changed the answer is "notModified": true with the heavy blocks left out.
languagesThe dictionary for the language asked for, with langFingerprint playing the same conditional trick for it alone.

Before you publish anything, the same command runs and is answered:

404 Not Found:

{
  "code": "not_found",
  "message": "Configuration: no published configuration for app 'my-app' in this environment",
  "details": [
    {
      "type": "squiddy.v1.ErrorDetail",
      "value": "CIsnGgdTcXVpZGR5",
      "debug": { "exceptionCode": 5003, "hubName": "Squiddy" }
    }
  ]
}

That is not a failure of your setup — it already proves your key, your coordinates and your endpoint. The detail travels twice: value is the ErrorDetail as protobuf and debug is the same thing decoded for you to read. exceptionCode is the typed application code, so a client can branch on it without parsing prose.

With no key at all, or one that has been revoked:

401 Unauthorized:

{ "code": "unauthenticated", "message": "data-plane: api key required" }

And that is the quickstart. Back in the dashboard the guide has closed itself: the data plane records the first request it answers for an organization, so there was never anything to tick off by hand.

Where to go next