First working integration
AvailableA 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
- 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.
- 1Create an appDashboardDashboard → Apps → New app
Give it a name and pick a platform (any). The dashboard opens the new app.
- 2Get your publishable keyDashboardApps → your app → API keys
Copy a publishable key. It looks like an opaque string; treat it as public.
Client vs serverPublishable keys are safe in a mobile or browser binary. Signing secrets and any server-only credentials are not — see API keys & secrets. - 3Register a devicePOST
https://ctrlapp.krdcode.com/api/public/sdk/v1/registerAuth:Authorization: Bearer <PUBLISHABLE_KEY>Upserts one device. device_uid is any stable string you generate on the client (a UUIDv4 is fine).
bashcurl -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 result200 OK. Body includesdevice_id(server-assigned uuid — store it),config(block state + min version),firebase_config(may benull), andpolicy(privacy / screen-capture policy). It does NOT echodevice_uid. - 4Create a feature flagDashboardApps → your app → Feature flags → New flag
Key:
welcome_banner. Default treatment:off. Save. - 5Sync from the "device"GET
https://ctrlapp.krdcode.com/api/public/sdk/v1/flags/rulesetAuth:Authorization: Bearer <PUBLISHABLE_KEY>Returns the whole flag ruleset for the app. The SDK evaluates it locally per device.
bashcurl https://ctrlapp.krdcode.com/api/public/sdk/v1/flags/ruleset \ -H "Authorization: Bearer <PUBLISHABLE_KEY>"Expected resultA JSON object withflags: [ { key: "welcome_banner", default_treatment: "off", ... } ]. - 6Flip the flag onDashboardFeature flags → welcome_banner → Default treatment → on → Save
Re-run the previous curl.
default_treatmentnow returns"on". - 7Prove the kill-switch loopPOST
https://ctrlapp.krdcode.com/api/public/sdk/v1/sessionAuth:Authorization: Bearer <PUBLISHABLE_KEY>Called by the SDK on every app launch. Returns the current block decision — used for kill-switch and forced updates.
bashcurl -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
blockorforce_updatewith a human message.
- 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.
- If you see
401 Unauthorized— theAuthorizationheader is missing or the key does not belong to this app. Re-copy from Apps → API keys. - If you see
404 Not Found— either 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 change — make 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.