Skip to main content

Consuming variables

Everything here rests on one call:

GET /variablevalues?set={id}&tag={Group/Tag}

which returns a flat name-to-string map — deliberately, so it can be poured straight into environment variables or a settings file without anything having to walk a structure first.

Setting up the consumer's account

A consumer should hold as little as possible. For a deployment that only reads:

PermissionWhy
VariableReadRequired by /variablevalues
VariableReadSecretsOnly if the deployment needs actual secrets rather than hints

VariableList is not needed — the consumer knows which sets it wants.

  1. Create a group holding exactly those.
  2. Create an account for the consumer and put it in that group.
  3. Sign in as that account and create an API key for it.
tip

VariableReadSecrets is what separates a deployment that can read secrets from one that cannot. If your pipeline injects secrets from a different vault and only wants non-sensitive config from TagShape, leave it off — the sensitive entries will come back as hints, which are harmless.

In a shell script

#!/usr/bin/env bash
set -euo pipefail

JWT=$(curl -sS -D - -o /dev/null -X POST "$IDENTITY_API/apikeyjwt" \
-H "x-tagshape-api: $TAGSHAPE_API_KEY" \
| awk 'BEGIN{IGNORECASE=1} /^x-tagshape-auth:/ {print $2}' | tr -d '\r')

[ -n "$JWT" ] || { echo "Could not exchange the API key for a token" >&2; exit 1; }

curl -sS --get "$LIBRARY_API/variablevalues" \
--data-urlencode "set=1" \
--data-urlencode "tag=Environment/$ENVIRONMENT" \
--data-urlencode "tag=Region/$REGION" \
-H "x-tagshape-auth: $JWT" \
> config.json

Turn it into environment variables:

while IFS=$'\t' read -r name value; do
export "$name=$value"
done < <(jq -r '.items | to_entries[] | [.key, .value] | @tsv' config.json)

Exchange the key once per run, not per request — the JWT is good for its full duration (60 minutes by default).

In PowerShell

$response = Invoke-WebRequest -Method Post -Uri "$env:IDENTITY_API/apikeyjwt" `
-Headers @{ 'x-tagshape-api' = $env:TAGSHAPE_API_KEY }
$jwt = $response.Headers['x-tagshape-auth']

$query = "set=1&tag=Environment/$env:ENVIRONMENT&tag=Region/$env:REGION"
$config = Invoke-RestMethod -Uri "$env:LIBRARY_API/variablevalues?$query" `
-Headers @{ 'x-tagshape-auth' = $jwt }

foreach ($entry in $config.items.PSObject.Properties) {
[Environment]::SetEnvironmentVariable($entry.Name, $entry.Value)
}

In a .NET service

public sealed class TagShapeConfigurationProvider(HttpClient client, string[] tags, int[] sets)
{
public async Task<Dictionary<string, string>> LoadAsync(CancellationToken cancellationToken)
{
var query = string.Join("&",
sets.Select(set => $"set={set}")
.Concat(tags.Select(tag => $"tag={Uri.EscapeDataString(tag)}")));

var response = await client.GetFromJsonAsync<ListDataSetDictionary<string, string>>(
$"/variablevalues?{query}", cancellationToken);

return response?.Items ?? [];
}
}

The JWT belongs on the HttpClient's default headers as x-tagshape-auth, refreshed before it expires.

Several library sets

GET /variablevalues?set=1&set=2&tag=Environment/Production

Sets are walked in name order, not query-string order, and a variable present in two sets takes its value from the set that sorts later. If you rely on one overriding another, name them so the ordering is obvious — renaming a set can change which one wins.

Choosing tags at deploy time

Tags describe where you are, so they usually come from the same place the deployment target does:

# CI variables
TAGSHAPE_TAGS: "Environment/Production,Region/EU,Tier/Enterprise"
TAG_ARGS=()
IFS=',' read -ra TAGS <<< "$TAGSHAPE_TAGS"
for tag in "${TAGS[@]}"; do TAG_ARGS+=(--data-urlencode "tag=$tag"); done

curl -sS --get "$LIBRARY_API/variablevalues" --data-urlencode "set=1" "${TAG_ARGS[@]}" \
-H "x-tagshape-auth: $JWT"

Asking for a tag that does not exist is not an error — it simply matches nothing, and values fall back. That makes typos quiet, so validate the tag list against GET /tags in CI if it is assembled by hand.

Diagnosing an unexpected value

Use the preview endpoint. It runs identical resolution and returns the whole winning value with its tags:

curl -sS --get "$LIBRARY_API/variablevalues/preview" \
--data-urlencode "set=1" \
--data-urlencode "tag=Environment/Production" \
-H "x-tagshape-auth: $JWT" | jq '.items.DatabaseConnection'

The tags on the winner tell you immediately whether the problem is a mistagged value or a tag you forgot to ask for. The usual cause is the fourth rule of resolution: a value carrying a tag you did not ask for cannot win.

Failure modes

SymptomCause
400 Bad RequestNo set parameter. At least one is required.
404 Not FoundA set names a library set that does not exist, or belongs to another organization. The whole request fails, not just that set.
403 ForbiddenThe account lacks VariableRead.
Secrets come back as hintsThe account lacks VariableReadSecrets.
A variable is missing from the responseIt has no untagged default and nothing matched. Add a default value.
The wrong valueUse /variablevalues/preview and check the winner's tags.