Smart Tags
Virtual tags derived from tagging policies you define — each policy enforces a tag key and builds its value from the resource's own fields. Applied for cost attribution only, never written back to the cloud; reviewable and reconciled on every refresh.
Smart tags are virtual tags ZopNight derives from tagging policies you define. Each policy enforces a tag key and derives its value from the resource’s own fields, so the result is reproducible and cheap to re-run. Smart tags are applied inside ZopNight for cost attribution only; they are never written back to the cloud provider.
How derivation works
- You create a tagging policy: an optional
selector(which resources it applies to — by provider, type, region, …) plus atagspec (the key, and the value built from resource fields). - The recommender resolves each resource against its policies. For a match, it derives the value:
fields → join → standardize(e.g.res.provider+res.regionjoined by-, lowercased →gcp-us-central1). - Derived tags land as pending. They are never auto-applied to cost — you accept the ones you want (or revoke later).
pending = derived − accepted. There is no “rejected” state.
Value source fields are restricted to stable resource attributes — res.type, res.region, res.provider, res.instance_type, res.name. Empty parts are skipped so a partially-absent multi-field value never produces separator garbage; an all-empty value omits the tag (there is no literal fallback).
Lifecycle & reconciliation
Tags are re-derived per resource on each resource.discovered event and across the org on a full refresh (POST /recommendations/refresh). Every re-derivation reconciles your accepted tags: an accepted tag is kept only if it is still derived with the same value, otherwise it is dropped — so disabling a policy or changing its value automatically removes the now-unsourced tag on the next refresh. When a resource is deleted in the cloud, its smart-tag row is removed.
List Smart Tags
/smart-tags Paginated per-resource derived/accepted tags for the current org, plus org-wide pending/accepted counts for the tab badges.
Query Parameters
| Parameter | Description |
|---|---|
status | Lifecycle filter: pending | accepted. Omit for all. |
provider | Cloud provider filter: aws | gcp | azure. |
page | Page number (default: 1). |
size | Items per page (default: 20, max: 100). |
{ "data": { "items": [ { "resourceUid": "//artifactregistry.googleapis.com/projects/acme/locations/us-central1/repositories/web", "resourceName": "web", "resourceType": "artifact-registry", "provider": "gcp", "cloudAccountId": "acc_1", "derived": { "cost-allocation": "gcp-us-central1", "cloud-platform": "gcp" }, "accepted": { "cloud-platform": "gcp" }, "pending": { "cost-allocation": "gcp-us-central1" } } ], "hasMore": false, "limit": 20, "counts": { "pending": 132, "accepted": 6 } }}Accept or Revoke
/smart-tags Promote pending tags into cost attribution (accept) or remove them (revoke). Body-based so resourceUid may contain slashes (e.g. GCP //... paths).
Send accepted: true to accept or accepted: false to revoke. Name the keys with keys: [...], or pass all: true (accept only) to act on every derived key. A mutation with no keys and all unset is rejected — it would otherwise silently no-op.
curl -X PATCH https://zopnight.com/api/smart-tags \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "resourceUid": "//artifactregistry.googleapis.com/projects/acme/locations/us-central1/repositories/web", "keys": ["cost-allocation"], "accepted": true }'curl -X PATCH https://zopnight.com/api/smart-tags \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "resourceUid": "i-0abc123def456", "all": true, "accepted": true }'curl -X PATCH https://zopnight.com/api/smart-tags \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "resourceUid": "i-0abc123def456", "keys": ["cost-allocation"], "accepted": false }'Tagging Policies
Tagging policies are stored in the generic policy store and managed through the standard policy CRUD endpoints with domain: "tagging". The recommender serves the form vocabulary and validates a spec before you create it.
/policies Create a tagging policy (domain=tagging).
curl -X POST https://zopnight.com/api/policies \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "domain": "tagging", "targetType": "organisation", "name": "cost-allocation", "spec": { "selector": { "all": [{ "attr": "res.provider", "op": "eq", "values": ["gcp"] }] }, "tag": { "key": "cost-allocation", "value": { "fields": ["res.provider", "res.region"], "join": "-", "standardize": true } } }, "enabled": true }'/tagging/policies/catalog Form vocabulary: selectable condition facets, operators, and the allowlisted value-source fields.
/tagging/policies/validations Validate a tagging spec before create. Returns { valid, errors[] }.