Skip to content

Services

A service is one discrete software component in your account: payments, web, notifications-worker. Every SDK client identifies itself with a service name when it boots, and the platform uses that identity to scope telemetry, attribute flag evaluations, and segment logger discovery.

A concrete example

You run three things:

  • payments — a Python backend
  • web — a TypeScript single-page app
  • notifications-worker — a Go worker

Each runs the SDK with a distinct service value:

python
from smplkit import SmplClient

with SmplClient(environment="production", service="payments") as client:
    pass

The first time each service boots, smplkit creates a service row automatically. The console shows three services running in production, plus whichever environments each one has reached.

How services are registered

When the SDK initializes, it sends a single bulk request to /api/v1/contexts/bulk containing both the environment and the service. If either doesn't exist yet, the platform creates it with name = key. If both already exist, the call is a no-op.

This is fire-and-forget — the SDK doesn't block on it, and a network hiccup doesn't prevent your app from starting. The next successful boot fills in whatever was missed.

You don't have to pre-create services or list them anywhere. The set of services is whatever your code is actually running.

Services are stored as contexts

Under the hood, services are stored as context instances under a built-in context type with key service. That's why the SDK's service parameter ends up in flag evaluations as a service context — your targeting rules can match on {"var": "service.key"} to vary behavior between payments and web without any extra wiring. See Contexts and context types.

Because services are contexts, they're managed through both the dedicated services API and the contexts API:

  • GET /api/v1/services — list all services
  • GET /api/v1/services/{key} — fetch one
  • PUT /api/v1/services/{key} — rename
  • DELETE /api/v1/services/{key} — remove (rarely needed)

How services scope telemetry

Several pieces of platform data are partitioned by service:

  • Flag sources. Each (flag, service, environment) combination is a row in flag_source — so the console can show which services declared this flag, with what type, in which environments. Drift across services (different defaults, different types) shows up as separate rows.
  • Logger sources. Same idea: logger_source rows track which services have observed which loggers in which environments. A logger's last_seen is per-source, so you can see exactly where it's still active.
  • Service-scoped flag evaluations. Every flag evaluation automatically includes the SDK's service in the context ({"service": {"key": "payments"}}), so rules can target services without any per-call boilerplate.

If you remove or rename a service, the SDK's next boot will recreate it with the new name. This means renaming through the API only sticks if you also update your deployment configuration.

Limits

Services are stored as context instances and share that pool:

  • 10,000 context instances per account. This includes services and any other context types you create.

There's no separate "services per account" cap.

Who can do what

ActionOWNERADMINMEMBERVIEWER
Read services
Create, rename, delete
Auto-register (via SDK)

The SDK auto-registration runs as the API key's role, which is OWNER for the bootstrap flow and whatever the minting role chose otherwise. Service auto-registration is a write, so the API key must have at least MEMBER permissions.

See Roles and permissions.