Upsert semantics, per this API's standard {originOrId} convention: if {originOrId}
resolves to an existing rule, it's updated; if it doesn't resolve to anything, a new
rule is created for non-UI (machine token/OAuth) callers only --
- if
{originOrId}looks like a UUID, the new rule is created with that UUID as its
dash0.com/id(metadata.labels["dash0.com/origin"]in the body, if any, is
stamped normally perPOST's rules); - otherwise,
{originOrId}itself becomes the new rule'sdash0.com/originand a
freshdash0.com/idis generated.
A UI (Clerk session token) caller gets a strict 404 instead of a create when
{originOrId} doesn't resolve -- the UI creates rules via POST only, matching this
API's other single-/api/-family resources.
metadata.labels["dash0.com/origin"] is immutable after creation: a value supplied on
update is silently ignored, never rejected, so a normal GET -> edit spec -> PUT round
trip doesn't need to strip it back out.
metadata.labels["dash0.com/dataset"]/spec.serviceNamespace/spec.serviceName are immutable; a value that
disagrees with the stored row is rejected with 400 and the row is left unchanged.
Setting spec.ownership to auto_derived is rejected with 400; the only accepted
transition is auto_derived -> user_defined (promoting a Miner-inferred rule).
Unlike POST, spec.status is required on every PUT -- there is no default, since
omitting it could otherwise silently reactivate or deactivate a rule the caller did
not intend to touch.
If the incoming payload is identical to what's already stored, the write is skipped
entirely and the existing rule is returned as-is, without bumping
dash0.com/updated-at -- so re-applying the same manifest (a normal IaC workflow)
never spuriously conflicts with itself.
| Time | Status | User Agent | |
|---|---|---|---|
Retrieving recent requests… | |||
