Profila Sign up

API Docs

The Profila Brand API — declared signals, creatives, MCP, OpenRTB 2.6.

Brand API

Developer reference

Profila is a consent-aware supply-side platform. Consumers declare purchase intent in the app — a signal — and brands respond with their own inventory over REST, MCP, or OpenRTB 2.6. You receive declared, privacy-safe targeting only — never names, emails, IPs, device ids, cookies, or precise location.

Base URLhttps://api.profila.com
AccessVerified brands only.
AuthA brand API key, keyId.secret, minted in the brand portal.
Brand API

Status

What's live today

CapabilityStatus
Mint / revoke API keys (brand portal) Live
Inbound REST — pull signals, push creatives, read logs Live, callable now
Inbound MCP server (/mcp, 4 tools) Live, callable now
Overview counters (endpoints, signals, bid requests, creatives) Live — real counts
Outbound OpenRTB 2.6 — Profila POSTs bid requests to your DSP Enabled, dormant until you activate a bid endpoint

The outbound auction only wakes once a brand registers and activates a bid endpoint. Until then the platform serves signals through its own content path and outbound counters read 0.

Brand API

Concepts

The vocabulary

TermMeaning
Signal A consumer's declared purchase intent, AI-classified into an IAB category + vertical + readiness + preferences. Identified only by an anonymous token (e.g. AU-EU-3841) and an opaque signalUuid — never a person.
Matching A signal reaches you two ways: brand (the consumer named your brand, matched by your domain) or category (the signal’s IAB category matches one your endpoint serves).
Creative A native sponsored card you supply for a matching signal. It renders in that consumer’s feed, tagged with the signal code.
Bid endpoint Your own OpenRTB responder URL. Profila POSTs privacy-first bid requests to it and ingests the winning creative.
API key A keyId.secret pair authenticating the inbound REST + MCP surfaces.
Routing mode brand_specific, marketplace_category, or both — how signals reach an endpoint.

Two directions, use either or both. Inbound — you pull matching signals and push creatives (REST or MCP). Outbound — Profila sends you OpenRTB bid requests.

Brand API

Getting access

From verified brand to first call

  • Get verified. Your brand account must be verified. Request it at [email protected].
  • Open the API tab. Brand portal → Customers → API (verified brands only).
  • Mint an API key. The secret is shown once — copy keyId.secret immediately. Revoke and re-mint anytime.
  • Optionally register a bid endpoint for the outbound flow.

A key looks like pk_ab12cd34.sk_9f8e7d6c… — the pk_ half is the public key id, the sk_ half is the secret. Profila stores only a hash of the secret; it can be re-minted, never recovered.

Brand API

Authentication

Every inbound request carries the key

Either header works:

Authorization: Bearer pk_ab12cd34.sk_9f8e7d6c…

x-api-key: pk_ab12cd34.sk_9f8e7d6c…
  • Scopes — minted with signals:read + creatives:write by default. Pushing creatives needs creatives:write.
  • Rate limit — 120 requests / minute / brand. Over the limit → 429 rate_limited.
  • Errors401 unauthorized · 403 forbidden · 400 invalid body · 422 validation · 429 rate_limited.
Brand API

Inbound REST

GET /api/brand/openrtb/signals

List anonymous signals that currently match your inventory. Query: limit (1–100, default 50).

curl -s "https://api.profila.com/api/brand/openrtb/signals?limit=20" \
  -H "Authorization: Bearer pk_ab12cd34.sk_9f8e7d6c…"
{
  "signals": [
    {
      "signalUuid": "0f6c8e2a-…",
      "anonymousToken": "AU-EU-3841",
      "vertical": "automotive",
      "readiness": "ready",
      "iabContentCategory": "IAB2-2",
      "iabContentCategoryName": "Auto Type",
      "preferences": ["electric", "SUV"],
      "country": "CH",
      "matchReason": "category",
      "createdAt": "2026-06-21T10:00:00.000Z"
    }
  ]
}
FieldNotes
signalUuid Opaque signal id — use it to push a creative.
anonymousToken Human-readable signal code shown to the consumer.
vertical, readiness Declared classification (e.g. automotive, ready).
iabContentCategory(Name) IAB content taxonomy code + label.
preferences Declared preferences, PII-scrubbed.
country Coarse country code only.
matchReason brand (consumer named you) or category (IAB match).

No name, email, phone, IP, device id, or precise location is ever returned.

Brand API

Inbound REST

POST /api/brand/openrtb/creatives

Push a native creative for one of your matching signals. Requires creatives:write.

curl -s -X POST https://api.profila.com/api/brand/openrtb/creatives \
  -H "Authorization: Bearer pk_ab12cd34.sk_9f8e7d6c…" \
  -H "content-type: application/json" \
  -d '{
    "signalUuid": "0f6c8e2a-…",
    "title": "BMW iX — all-electric SAV",
    "description": "Up to 600 km range. Book a test drive.",
    "imageUrl": "https://www.bmw.com/…/bmw-ix.png",
    "clickUrl": "https://www.bmw.com/en/all-models/bmw-i/ix",
    "cta": "Configure yours",
    "sponsoredBy": "BMW",
    "adomain": ["bmw.com"]
  }'
FieldReqNotes
signalUuid Must be one of your matching signals (else 422).
title Card headline.
description Card body.
imageUrl Must be an http(s) URL.
clickUrl Must be an http(s) URL. Click-through destination.
cta Button label (e.g. "Configure yours").
sponsoredBy Sponsor label shown on the card.
adomain Advertiser domain(s).
price, crid Optional bid price / creative id for your records.

Response { "ok": true }, or 422 if the signal doesn't match or the creative isn't renderable. On success the card enters that consumer's feed as a sponsored item.

Brand API

Inbound REST

GET /api/brand/openrtb/logs

Recent bid requests Profila sent to your endpoints (outbound flow). Query: limit.

Each entry: requestId, dspEndpointId, categoryIds, impCount, responseTimeMs, hadBid, createdAt.

Brand API

MCP server

The same inbound surface, over MCP

Streamable-HTTP JSON-RPC 2.0 for LLM/agent runtimes. Endpoint POST https://api.profila.com/mcp, same key on Authorization or x-api-key, protocol version 2024-11-05.

ToolArgumentsDoes
list_matching_signals { limit?: number } (1–100) Your matching signals.
get_signal_detail { signalUuid } One matching signal's detail.
submit_creative { signalUuid, title, description, imageUrl, clickUrl, cta?, … } Push a creative (needs creatives:write).
get_delivery_stats {} { matchingSignals, bidRequests, creativesServed }.
# Handshake
curl -s -X POST https://api.profila.com/mcp -H "content-type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'

# List tools
curl -s -X POST https://api.profila.com/mcp \
  -H "Authorization: Bearer pk_ab12cd34.sk_…" -H "content-type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

# Call a tool
curl -s -X POST https://api.profila.com/mcp \
  -H "Authorization: Bearer pk_ab12cd34.sk_…" -H "content-type: application/json" \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call",
       "params":{"name":"list_matching_signals","arguments":{"limit":5}}}'
Brand API

Outbound · OpenRTB 2.6

Register a bid endpoint

Profila POSTs an OpenRTB 2.6 bid request to your responder whenever a matching signal appears, then ingests your winning creative. Register in the portal (API tab → Register endpoint):

  • Bid URL — your responder, e.g. https://dsp.yourbrand.com/openrtb/bid
  • Routing — brand + category / brand only / category only
  • Auth — None / Bearer token / API-key header
  • Categories — IAB codes you serve, e.g. IAB2, IAB20

New endpoints start pending — click Activate to receive traffic. First-price (at: 1), tmax default 200 ms.

Brand API

Outbound · OpenRTB 2.6

The bid request Profila sends

{
  "id": "<request uuid>",
  "at": 1,
  "tmax": 200,
  "imp": [{
    "id": "1",
    "banner": { "format": [{ "w": 300, "h": 250 }] },
    "bidfloor": 0, "bidfloorcur": "USD", "secure": 1,
    "ext": { "profilaBrandDomains": ["bmw.com"] }
  }],
  "site": {
    "id": "profila-web", "name": "Profila", "domain": "app.profila.com",
    "cat": ["IAB2-2"], "publisher": { "id": "profila", "name": "Profila GmbH" }
  },
  "device": { "devicetype": 2, "os": "Unknown", "dnt": 0, "lmt": 1 },
  "user": {
    "id": "<daily-rotating opaque hash>",
    "data": [
      { "name": "profila-declared-categories",
        "segment": [{ "id": "IAB2-2", "name": "IAB2-2" }] },
      { "name": "profila-classified-intent", "segment": [
        { "name": "vertical", "value": "automotive" },
        { "name": "readiness", "value": "ready" },
        { "name": "intent_type", "value": "purchase" },
        { "name": "timeframe", "value": "this_month" },
        { "name": "budget_range", "value": "40000-60000 CHF" }
      ] }
    ]
  },
  "regs": { "coppa": 0, "ext": { "gdpr": 1, "us_privacy": "1YNN" } },
  "source": { "schain": { "ver": "1.0", "complete": 1,
    "nodes": [{ "asi": "profila.com", "sid": "profila-ssp", "hp": 1 }] } }
}
  • bidfloor is always 0 — Profila does not charge per impression.
  • user.id is a daily-rotating SHA-256 hash — no buyeruid, IP, or device id.
  • lmt: 1 and regs.ext.gdpr: 1 are always set.
Brand API

Outbound · OpenRTB 2.6

The bid response Profila expects

Return a standard BidResponse. The winning creative is read from bid.ext:

{
  "id": "<same request id>",
  "cur": "USD",
  "seatbid": [{
    "seat": "your-seat",
    "bid": [{
      "id": "b1", "impid": "1", "price": 6.5,
      "adomain": ["bmw.com"],
      "crid": "creative-123",
      "ext": {
        "title": "BMW iX — all-electric SAV",
        "description": "Up to 600 km range. Book a test drive.",
        "imageUrl": "https://www.bmw.com/…/bmw-ix.png",
        "clickUrl": "https://www.bmw.com/en/all-models/bmw-i/ix",
        "cta": "Configure yours",
        "sponsoredBy": "BMW"
      }
    }]
  }]
}

Empty seatbid (or HTTP 204) to no-bid. Profila validates the bid against the signal, logs it, and renders the winner in the consumer's feed. HTTPS only, no redirects, capped response size.

Brand API

Privacy guarantees

What's sent, what's never sent

Sent to brandsNever sent
Anonymous token (rotating) Name, email, phone, address
Declared IAB category + intent segments IP address, device id / IFA
Readiness, budget range, preferences (scrubbed) Cookies, cross-site identifiers
Coarse country, regs.ext.gdpr = 1 Precise location, real user id

Enforced in the bid-request builder and creative-ingest path, and asserted by automated tests. Every consumer sees, in-app, exactly what declared data was sent.