Identifier contract
Identifier contract
A profile is keyed by (app_id, user_key). Context merges last-write-wins per trait. user_key is opaque and is never expanded onto a landing URL.
Serve request
Each decision is { placement, user_key, context }. The public app key prefix travels in X-App-Key, not in the JSON body. Placement is the placement name on the authenticated app.
{
"placement": "home",
"user_key": "user-42",
"context": {
"plan": "pro",
"country": "US",
"locale": "en-US",
"device": "desktop"
}
}user_key
user_key is an opaque publisher identifier. Meridian Ads does not assume it is PII. If the value looks like an email, it is hashed at rest with SHA-256 of the lowercase string. Other keys are stored as given (trimmed).
Frequency caps and profile lookup use the normalized key. GDPR or publisher delete (DELETE /api/v1/apps/{appId}/profiles/{userKey}) removes the Redis hot copy and the Postgres durable copy.
context
context is a JSON object of traits. Max size is 8KB. On each decision the request map is merged into the stored profile with last-write-wins per trait key, then segments run on the merged profile. There are no first-class geo, device, or daypart objects in v1. Send those as traits if you have them.