First working integration

Available

A truly runnable REST-first tutorial: create an app, get a key, register a device, sync, flip a flag, verify.

Outcome
A device that sees a live flag flip from the dashboard.
Time
~10 minutes
Prerequisites
  • A CtrlApp account (free plan is fine).
  • curl available in a terminal.

You will create an app, generate a publishable key, register one device with curl, sync state, flip a feature flag from the dashboard, and see the change come back on the next sync. No SDK required.

  1. 1
    Create an app
    DashboardDashboard → Apps → New app

    Give it a name and pick a platform (any). The dashboard opens the new app.

  2. 2
    Get your publishable key
    DashboardApps → your app → API keys

    Copy a publishable key. It looks like an opaque string; treat it as public.

    Client vs server
    Publishable keys are safe in a mobile or browser binary. Signing secrets and any server-only credentials are not — see API keys & secrets.
  3. 3
    Register a device
    POSThttps://ctrlapp.krdcode.com/api/public/sdk/v1/register
    Auth: Authorization: Bearer <PUBLISHABLE_KEY>

    Upserts one device. device_uid is any stable string you generate on the client (a UUIDv4 is fine).

    bash
    curl -X POST https://ctrlapp.krdcode.com/api/public/sdk/v1/register \
      -H "Authorization: Bearer <PUBLISHABLE_KEY>" \
      -H "Content-Type: application/json" \
      -d '{
        "device_uid": "<DEVICE_ID>",
        "platform": "web",
        "app_version": "0.1.0",
        "locale": "en"
      }'
    Expected result
    200 OK. Body includes device_id (server-assigned uuid — store it), config (block state + min version), firebase_config (may be null), and policy (privacy / screen-capture policy). It does NOT echo device_uid.
  4. 4
    Create a feature flag
    DashboardApps → your app → Feature flags → New flag

    Key: welcome_banner. Default treatment: off. Save.

  5. 5
    Sync from the "device"
    GEThttps://ctrlapp.krdcode.com/api/public/sdk/v1/flags/ruleset
    Auth: Authorization: Bearer <PUBLISHABLE_KEY>

    Returns the whole flag ruleset for the app. The SDK evaluates it locally per device.

    bash
    curl https://ctrlapp.krdcode.com/api/public/sdk/v1/flags/ruleset \
      -H "Authorization: Bearer <PUBLISHABLE_KEY>"
    Expected result
    A JSON object with flags: [ { key: "welcome_banner", default_treatment: "off", ... } ].
  6. 6
    Flip the flag on
    DashboardFeature flags → welcome_banner → Default treatment → on → Save

    Re-run the previous curl. default_treatment now returns "on".

  7. 7
    Prove the kill-switch loop
    POSThttps://ctrlapp.krdcode.com/api/public/sdk/v1/session
    Auth: Authorization: Bearer <PUBLISHABLE_KEY>

    Called by the SDK on every app launch. Returns the current block decision — used for kill-switch and forced updates.

    bash
    curl -X POST https://ctrlapp.krdcode.com/api/public/sdk/v1/session \
      -H "Authorization: Bearer <PUBLISHABLE_KEY>" \
      -H "Content-Type: application/json" \
      -d '{ "device_uid": "<DEVICE_ID>", "platform": "web", "app_version": "0.1.0" }'

    Create a rule in Apps → your app → Block rules that matches everyone, then re-run the request. The response now includes an action such as blockor force_update with a human message.

Verify it
  • You saw a 200 response from /register with a device_id, config, firebase_config, and policy in the body.
  • Toggling default_treatment in the dashboard changed the value returned by /flags/ruleset.
  • Adding a Block rule changed the decision returned by /session.
Common mistakes
  • If you see 401 Unauthorizedthe Authorization header is missing or the key does not belong to this app. Re-copy from Apps → API keys.
  • If you see 404 Not Foundeither the URL path is wrong (verify /api/public/sdk/v1/<name>, no trailing slash) or the target app / device / form / post could not be found for this key. Check both before assuming a typo.
  • If the flag value does not changemake sure you edited the Default treatment, not just a rule, and that you queried the same app's key.

Now do the same from real code: pick a language in Choose an integration.

Back to top