Documentation Index
Fetch the complete documentation index at: https://docs.trygravity.ai/llms.txt
Use this file to discover all available pages before exploring further.
The primary ad endpoint. Send conversation messages and get back a contextually matched ad with generated creative.
Your Gravity API key. Format: Bearer <key>
Body
Conversation history. Array of {role, content} message objects. The engine uses the last few messages for contextual matching.
Session identifier. Used for frequency capping, experiment bucketing, and reporting. If the Gravity pixel is installed and you’re on @gravity-ai/api ≥ 1.1.7, the SDK auto-forwards the pixel’s gr_sess_-prefixed session ID (30-min idle timeout, 1-day max) via window.gravityPixel.getSessionId(). Pass your own sessionId to override if you have a better session scope.
Ad placement configuration. 1–10 placements per request.| Field | Type | Description |
|---|
placement | string | Placement type. One of above_response, below_response, inline_response, left_response, right_response, search_result, top_page, bottom_page, center_page, left_page, right_page. |
placement_id | string | Unique slot identifier on your side. Ties dashboard analytics back to the spot in your UI. |
Optional. User context for targeting and attribution. All fields are optional on the wire — the engine accepts any shape and passes extras through.| Field | Type | Description |
|---|
id | string | Stable per-user identifier on your side. Used for frequency capping, attribution, and identity linking. The SDK defaults this to "anonymous" if you don’t supply one. |
ip | string | User’s IP address. Auto-populated by the SDK from the incoming request. |
hashed_email | string | SHA-256 of email.strip().lower(). Passing this significantly improves attribution; see Data quality. |
hashed_phone | string | SHA-256 of digits-only phone. |
Extra fields (gender, age, subscription tier, interests, etc.) are accepted and stored as request context.
Optional. Device signals. The SDK auto-populates this from the client; for direct HTTP you should at least send ip for geo-targeting and fraud detection. Fields: ip, ua, country, os, ifa, plus any extras (timezone, locale, browser, etc.).
Optional. Minimum relevancy threshold, 0.0–1.0. When omitted, the engine falls back to the publisher baseline configured in your dashboard. Both SDKs default to 0.2.
Optional. Array of topic strings to exclude from matching (e.g. ["politics"]).
Optional. When true, returns test creative and skips billing/metrics. The SDKs set this from the inverse of their production flag.
curl -X POST https://server.trygravity.ai/api/v1/ad \
-H "Authorization: Bearer <your_publisher_api_key>" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "How do I set up a PostgreSQL database?"},
{"role": "assistant", "content": "Here are the steps to set up PostgreSQL..."}
],
"sessionId": "sess_abc123",
"placements": [
{"placement": "below_response", "placement_id": "main"}
],
"user": {"id": "user_789"}
}'
Response
On a successful match the endpoint returns HTTP 200 with a JSON array of ad objects — one per requested placement:
[
{
"adText": "Serverless Postgres that scales to zero. Start free.",
"title": "Neon Serverless Postgres",
"brandName": "Neon",
"cta": "Try Neon Free",
"url": "https://neon.tech",
"favicon": "https://icons.duckduckgo.com/ip3/neon.tech.ico",
"clickUrl": "https://api.trygravity.ai/track/click?p=...",
"impUrl": "https://api.trygravity.ai/ack?p=...",
"placement": "below_response",
"placement_id": "main"
}
]
The SDKs wrap this array in a convenience object — { ads, status, elapsed } in JS, AdResult(ads, status, elapsed_ms, ...) in Python — but that envelope is SDK-only and does not appear on the wire.
Ad object
| Field | Type | Description |
|---|
adText | string | Generated ad copy, contextually matched |
title | string | Product/campaign title |
brandName | string | Advertiser brand name |
cta | string | Call to action text |
url | string | Landing page URL |
favicon | string | Brand favicon URL |
clickUrl | string | Tracked click URL — use this for links |
impUrl | string | Impression pixel URL — fire when ad is visible |
placement | string | Echoes back the placement type this ad filled |
placement_id | string | Echoes back your slot correlation ID |
campaignId | string | Campaign identifier for the matched ad |
leadForm | object | Lead form configuration, when the campaign has a lead form attached |
Null fields are omitted from the response.
When an experiment is active, the ad object also includes:
| Field | Type | Description |
|---|
variant | string | Human-readable arm label |
experiment_id | string | Canonical experiment ID |
composition_id | string | Per-render composition ID (unique per impression) |
renderer_key | string | Which renderer to use |
composition | object | Tokens and props for the assigned renderer |
Experiment identity is already baked into impUrl and clickUrl — downstream analytics join automatically.
Always use clickUrl for ad links (not url directly) and fire impUrl when the ad becomes visible. This ensures accurate tracking and billing.
No ad available
When no ad matches the context (or the request is filtered as a bot, times out, or hits an unrecoverable error), the endpoint returns an HTTP 204 No Content with an empty body — there is no JSON payload. Your UI should gracefully hide the slot in that case.