Skip to main content

Customer map

The customer map places every customer of a project and environment on one two-dimensional map. Customers who behave alike sit close together, and the groups the model has found are drawn as areas. Customers close together behave alike; distances between far-apart areas, and the size of an area, are only approximate.

There is one map for each project and environment. It is drawn from the embeddings of one deployment slot that the server chooses (or that an Admin chooses), and it is read in one call, getCustomerMap. Each time the map is updated, the server draws a new map and keeps the old one. The API calls each of these maps an edition. An edition is a projection_2d export of the slot, so its file is read like any other export, with GET /slots/{slot}/exports/{export_id}, which mints the signed link.

The map reads the groups the model already has. An update never builds or changes groups. If a model has no group build yet, the map shows no groups until an Admin finds them in the console.

The current map​

The map you see is the current map:

  1. While a pin is active, the pinned map.
  2. Otherwise the newest edition that is shown.
  3. Otherwise, while no shown edition exists, the newest finished map of the slot that carries group ids, else the newest finished map. A held map is never current.

A map can be held. A held map was kept back because it differs from the map before it by more than usual: it places far fewer customers than the map before it (and a smaller customer base does not explain it), or far fewer of its customers have a group. A held map is never current, and the previous map stays on screen. Admins see that a map was held and why.

Each new map is lined up with the current one, so customers stay close to where they were. When a new model replaces the old one, the map is drawn afresh and says so.

state in the answer says what is going on. Only one state is reported: the first of these that applies.

StateMeaning
no_modelNo slot qualifies yet, so there is no map.
no_mapA slot qualifies, but no map has been drawn.
first_map_pendingThe first map is being drawn.
pinnedAn Admin pinned a map, so nothing replaces it until the pin ends.
updatingA newer map is being drawn; the current map stays readable.
failedThe newest update failed; last_failure names it.
heldThe newest update was held; the current map is the one before it.
out_of_dateA scheduled update is overdue and has not started.
pausedAn Admin paused scheduled updates.
on_requestUpdates run only when someone presses Update now.
needs_adminNo credential is available to run scheduled updates, or it may not use the slot's purpose. See Who runs an update.
up_to_dateNone of the above: the current map is the latest one.

Which slot feeds the map​

A slot can feed the map when it is active, has an active bundle, runs live, serves a sequence model and has a purpose that you may use. Without a choice, the server picks one: first a slot whose maps already carry group ids (a batch-only slot first), then a slot with a current group build, then a batch-only slot, then the newest activation. The choice is stored and kept while that slot still qualifies, so adding another slot never moves the map.

An Admin can choose the slot in the map settings. Update now and scheduled updates never switch slot by themselves: if the chosen slot stops qualifying, Update now is refused with the reason and scheduled updates fail where Admins can see them. Reads do switch: while the chosen slot does not qualify, the map shows the slot the server would choose for you, without its schedule or pin. The Admin's map settings still name the chosen slot; Update now and saving the settings say why it no longer qualifies (slot_not_eligible, or model_family_not_supported for an event model). The same holds for a stored slot that you may not use: your reads show the automatic choice among the slots you may use. ?slot= shows another slot's map, read-only (403 permission_denied for a slot you may not use).

When the map updates​

Every project whose map has customer groups gets default settings: nightly at 03:00 UTC. A map with no standing credential to run as waits for an Admin (needs_admin). An Admin can change the settings with putCustomerMapSettings or in the console's map settings.

frequencyUpdatesNeeds
nightlyevery day at local_timenone
weeklyone day a week at local_timeweekday: 1 (Monday) to 7 (Sunday)
monthlyone day a month at local_timeday_of_month: 1 to 28
customevery every_hours hoursevery_hours: 1 to 168, so never more often than hourly
on_requestonly when someone presses Update nownone
  • Time zone. local_time (HH:MM, default 03:00) is in time_zone, an IANA name such as Europe/London. The default is UTC. An Admin sets the zone; the console pre-fills the Admin's browser zone but saves it only when the Admin presses Save. Updates follow daylight-saving changes in the chosen zone. Host-local names (localtime, posix/…, right/…) are refused.
  • Pause. paused: true stops scheduled updates and keeps the cadence. Update now still works while the map is paused or set to on_request.
  • One a day. For nightly, weekly and monthly maps, at most one scheduled update runs for each local date; a time that an Admin saves later the same day still runs that day.
  • Next update. next_run_at is the next scheduled update. It is null while the map is paused, pinned, on request, waiting for an Admin, or when the slot is one you may not use.
  • Cost controls. One update runs at a time for a map, and the cooldown, the daily cap and the pin below apply. Map updates meter nothing.

The settings are one document that you replace as a whole. Read it, change what you need and send it back with the updated_at you read:

{
"slot_id": null,
"frequency": "weekly",
"local_time": "03:00",
"time_zone": "Europe/London",
"weekday": 1,
"paused": false,
"cooldown_minutes": 15,
"pin": null,
"expected_updated_at": null
}

expected_updated_at guards against two Admins saving at once. If the settings changed since you read them, the save is 400 failed_precondition with reason version_mismatch and nothing changes. Use null while no settings are stored yet. Until then a read returns the defaults, with created_at and updated_at null, and writes nothing. With no stored settings, runs_as is none and next_run_at is null, unless the project and environment has a succeeded map with customer groups; then they show the nightly default and, when a standing credential requested that map, who it would run as.

Update now​

Update now (refreshCustomerMap) starts a new map straight away. Members and Admins can use it; Viewers cannot. An API key needs the admin scope, and applications are refused.

It takes no body. Every update uses the same fixed recipe: every customer up to 200,000, the same seed, and the map's own colours. Nobody chooses columns, sample size or seed, which is why a Member may use it when creating an export stays with Admins.

The call runs these checks in order, and the first that fails answers:

  1. Permission. Role or key scope.
  2. The map's slot. The slot that is stored (for an automatic map, chosen again by the server's rule if it stopped qualifying), never a slot picked from what you may use. A chosen slot that no longer qualifies is 400 failed_precondition (slot_not_eligible, or model_family_not_supported for an event model); no slot at all is no_model.
  3. Purpose. A caller who may not use the slot's purpose gets 403 permission_denied (purpose_not_allowed) and learns nothing else about the map.
  4. Pin. map_pinned, with until.
  5. One at a time. While an update is queued or running, the call starts nothing and answers 202 with that update. An update still running on the slot the map followed before a slot change is update_in_progress, with retry_after.
  6. Groups. groups_missing while the newest update was held because groups were missing and the slot's group build has not changed since.
  7. Cooldown. cooldown, with retry_after.
  8. Daily cap. daily_cap, with retry_after.
  9. The update starts. 202 with the new edition.

The limits depend on who calls:

Admin sessionAnyone else
Cooldown after a successful updatethe map's cooldown_minutes (0 to 1,440; default 15)the larger of cooldown_minutes and 15 minutes
After a failed updatemay retry at once, but never inside the cooldown after a successwaits a backoff of min(effective cooldown, 2^n) minutes after n failures in a row, and never less than the cooldown after the last success
Updates started in 24 hours, for each mapno cap24

An Admin caller is a console session that holds customer_map.settings.put. Every API key counts as anyone else. A cooldown of 0 therefore applies to Admins only.

Several people pressing the button at once start one update: the others get the update already running, or, for a moment, 503 update_in_progress with a Retry-After to try again. An Idempotency-Key replays the first answer for 24 hours.

An update runs as the person (or key) who pressed Update now, so the job uses that caller's purposes. It is never run without a credential.

Pin and history​

An Admin can pin one map until a date. While the pin is active the pinned map is the current map, scheduled updates are skipped and Update now is refused with map_pinned. When the date passes, updates resume by themselves.

  • pin.until must be after now and at most 90 days ahead.
  • pin.export_id names a succeeded projection_2d export of the slot the map follows, coloured only by scores and group ids. Leave it out to pin the current map. Any other export of the project (another slot, one that did not succeed, one that is not projection_2d, or one coloured by event attributes) is 400 failed_precondition pin_export_not_eligible, so Members and Viewers never see such a column on the map.
  • An export that does not exist, or belongs to another project or environment, is 404 not_found. With no current map to pin the answer is 400 no_map.
  • Changing the slot while a pin on another slot is active is refused (pin_other_slot). Remove the pin in the same request, or first.
  • pin: null removes the pin.

The history (listCustomerMapEditions) lists the editions of the map's current slot, newest first, 50 at most per page, with cursor paging. Each entry gives the edition, what changed against the edition before it, and its layout and stability figures. Held editions are listed with verdict: held. The pinned map is listed too when it is not itself an edition, in date order and counted within the page limit. Editions of a slot the map no longer follows are not listed. An edition drawn before editions recorded a verdict or a layout reads not_recorded.

Who runs an update​

  • Update now runs as the caller.
  • Scheduled updates run as the Admin session, or the API key with the admin scope, that last saved the map settings (runs_as: admin). Before the first save, the settings take the requester of the newest successful map of the same slot, if that is a standing user or API key of the environment (map_requester). An application never qualifies.
  • The stored identity is checked again before every scheduled update. A person who was removed, a key that was revoked, a saver who no longer holds customer_map.settings.put, or a credential that may not use the slot's purpose no longer qualifies.
  • With no credential that qualifies, runs_as is none, no scheduled update runs until an Admin saves the settings, and the state reads needs_admin unless an earlier state in the table applies. Nothing ever runs without a credential.

Permissions​

The map has five permissions: three reads for everyone who can read the project, Update now for Members, and settings for Admins. The table, the built-in floors, the API key scopes and the extra limits on Update now are in Custom roles and SCIM provisioning. A custom role made before these permissions existed does not hold them.

Reads show only what the caller's purposes allow: a slot the caller may not use is left out, not refused, and so are its pin and next update time (naming that slot with ?slot= is refused). Started and joined updates, settings changes, and refusals for role, key scope or purpose are audited as customer_map.refresh and customer_map.settings.update.

Metering​

Map editions meter nothing. A scheduled update and an Update now emit no export_rows usage and never appear in usage. A projection_2d export that someone requests by hand with POST /slots/{slot}/exports still meters as before.

Webhooks​

Every map update publishes export.completed or export.failed, like any projection_2d export, and the event's data.kind is projection_2d. A receiver that wants only maps filters on data.kind. To tell an update from a projection someone requested by hand, look in a succeeded event's data.metadata: updates carry layout, verdict and alignment, and a manual projection carries none of them. See webhooks for delivery and signing.

The five operations​

OperationPathWhoWhat it does
getCustomerMapGET /customer-mapViewerThe current map, its state, the schedule and the pin.
refreshCustomerMapPOST /customer-map:refreshMemberUpdate now. Takes no body; accepts Idempotency-Key.
getCustomerMapSettingsGET /customer-map/settingsViewerThe schedule, time zone, cooldown, pin and whose credential runs updates.
putCustomerMapSettingsPUT /customer-map/settingsAdminReplaces the settings and the map's schedule together.
listCustomerMapEditionsGET /customer-map/editionsViewerThe history of the map.

All five are described in the customer map API reference. The map's schedule also appears in GET /schedules as a row of kind customer_map; see schedules.