> ## Documentation Index
> Fetch the complete documentation index at: https://docs.costgraph.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Pricing IDs

> Pin any resource to a rate you registered, per cost dimension

A resource running outside a supported cloud has no instance type, region or
provider ID for CostGraph to price against. Instead of inventing those, tag the
resource with the ID of a rate you registered in the pricing marketplace.

A pricing ID is per **dimension**, so one object can carry a compute rate and a
storage rate at the same time:

```
costgraph.ai/pricing-id.compute = <uuid>
costgraph.ai/pricing-id.storage = <uuid>
```

Register a rate once, then tag every resource that bills at it:

```mermaid theme={null}
flowchart LR
  R["Rate you registered<br/>in the marketplace"] -->|returns an ID| ID(["pricing ID"])
  ID -.->|pricing-id.compute| N["Node"]
  ID -.->|pricing-id.storage| V["Volume"]
```

The same ID can be tagged onto as many resources as bill at that rate, and
changing the rate reprices all of them at once.

## Dimensions

| Suffix      | Rate it points at     | Register with                                                                                                       |
| ----------- | --------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `.compute`  | compute rate          | [`POST /marketplace/providers/compute`](https://docs.costgraph.ai/api-reference/register-a-custom-provider)         |
| `.storage`  | disk rate             | [`POST /marketplace/providers/disks`](https://docs.costgraph.ai/api-reference/register-a-custom-disk-provider)      |
| `.database` | managed database rate | [`POST /marketplace/providers/databases`](https://docs.costgraph.ai/api-reference/register-custom-database-pricing) |
| `.model`    | model token rate      | [`POST /marketplace/providers/models`](https://docs.costgraph.ai/api-reference/register-custom-model-pricing)       |

A key with no suffix is read as `.compute` on a node and `.storage` on a volume.
Prefer the explicit suffix.

## Register a rate

Full request and response schema:
[Register a custom provider](https://docs.costgraph.ai/api-reference/register-a-custom-provider)
for compute, and
[Register a custom disk provider](https://docs.costgraph.ai/api-reference/register-a-custom-disk-provider)
for storage.

```bash theme={null}
curl -X POST https://pricing.baselinehq.cloud/marketplace/providers/compute \
  -H "Authorization: Bearer $COSTGRAPH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"entries":[{"service":"BaseCompute","region":"dc-east","instance_type":"bare-metal-xl","operating_system":"linux","cpu_cores":64,"ram_gb":512,"cost_per_hour":1.85,"period_billing_hours":730}]}'
```

A disk rate takes capacity bounds instead of CPU and memory:

```bash theme={null}
curl -X POST https://pricing.baselinehq.cloud/marketplace/providers/disks \
  -H "Authorization: Bearer $COSTGRAPH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"entries":[{"service":"BaseDisks","region":"dc-east","type":"nvme","usage_type":"ONDEMAND","cost_per_gb_hour":0.0002,"min_capacity_gb":0,"max_capacity_gb":65536,"period_billing_hours":730}]}'
```

The response carries an `id` for each entry. That UUID is what you tag with.

## Tag the resource

On Kubernetes, use labels:

```bash theme={null}
COMPUTE_ID="00000000-0000-0000-0000-000000000000"
STORAGE_ID="11111111-1111-1111-1111-111111111111"

kubectl label node/node-1 costgraph.ai/pricing-id.compute="$COMPUTE_ID" --overwrite
kubectl label nodes -l rack=r1 costgraph.ai/pricing-id.compute="$COMPUTE_ID" --overwrite
kubectl label pv/pv-1 costgraph.ai/pricing-id.storage="$STORAGE_ID" --overwrite
```

Review what is tagged with:

```bash theme={null}
kubectl get nodes -L costgraph.ai/pricing-id.compute
```

Pins are read from Kubernetes objects: nodes, volumes and volume claims.

A tagged resource needs no other metadata. CPU and memory still come from the
node's capacity, and volume size from the PV, because those are the billed
quantities.

## Key spellings

Some platforms reject the canonical key, and a label set on a cloud instance can
reach the node in a rewritten form. CostGraph matches keys case-insensitively
after replacing `/`, `.` and `-` with `_`, so every spelling below resolves to
the same pin.

| Spelling                          | Where it comes from                                                     |
| --------------------------------- | ----------------------------------------------------------------------- |
| `costgraph.ai/pricing-id.compute` | the canonical key                                                       |
| `costgraph.ai_pricing-id.compute` | Azure, whose tag names reject `/`                                       |
| `costgraph_ai_pricing_id_compute` | GCP, whose label keys allow only lowercase letters, digits, `-` and `_` |

Set whichever your tooling accepts.

## Inheritance

Every object is priced in its own right. An object with no pin of its own takes
the rate from the nearest scope above it, so tagging one node can price the
volumes on it without tagging each one.

```mermaid theme={null}
flowchart TD
  N["Node<br/>pricing-id.storage = A"]
  N -.->|default for| PV["Volume on that node<br/>inherits A"]
  PV2["Volume<br/>pricing-id.storage = B<br/>keeps its own rate"]
```

The nearest pin wins, and each kind of object looks outward along its own path:

```mermaid theme={null}
flowchart LR
  subgraph V["Volume"]
    direction TB
    v1["own pin"] --> v2["the node it is attached to"] --> v3["attribute matching"]
  end
  subgraph C["Volume claim"]
    direction TB
    c1["own pin"] --> c2["its volume"] --> c3["its namespace"] --> c4["the node"]
  end
  subgraph NODE["Node"]
    direction TB
    n1["own pin"] --> n2["attribute matching"]
  end
```

A volume and its claim are separate objects and can carry different rates. A
volume with no consumer has no node above it, so with no pin of its own it falls
straight to attribute matching.

<Note>
  A node is not in any namespace, so tagging a namespace never changes a node's
  own rate. It reaches the claims in that namespace.
</Note>

## What a pin changes

A pin decides the rate CostGraph uses to cost that resource, replacing attribute
matching for that dimension. Nothing else about the resource changes: CPU and
memory still come from the node's capacity and size from the volume, because
those are the billed quantities.

A pin is how a resource gets a cost at all when CostGraph has nothing to match
on, such as a bare-metal node with no cloud provider behind it.

## Change a rate

Re-POST the same entry with a new `cost_per_hour`. The ID is unchanged and every
tagged resource picks up the new rate from the next hour. Already-billed hours
keep the rate they were billed at.

<Warning>
  Changing `region`, `instance_type` or `period_billing_hours` creates a new rate
  with a new ID, because those describe a different SKU. Re-tag the affected
  resources with the new ID.
</Warning>

## Share a rate

Anyone holding the ID can tag with it, which is how a provider prices the
clusters they sell to. Only your own organisation's rates are listed back to you,
so treat an ID as a secret you hand out deliberately.

## Fix a mistake

Re-tag with the correct ID and the change applies on the next sync. Remove a
Kubernetes label with a trailing hyphen:

```bash theme={null}
kubectl label node/node-1 costgraph.ai/pricing-id.compute-
```

Removing the tag removes the pin. The resource falls back to a pin inherited
from an ancestor, then to normal attribute matching.

If the ID is malformed, or names a rate that has been deleted, CostGraph logs a
warning naming the resource and the value, and leaves that dimension unpriced. It
never falls back to attribute matching to cover for a bad ID.
