Skip to main content
POST
/
api
/
v1
/
ad
/
group
curl -X POST https://server.trygravity.ai/api/v1/ad/group \
  -H "Authorization: Bearer <your_publisher_api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "sessionId": "group-chat-abc",
    "messages": [
      {"role": "user", "content": "has anyone tried that new coffee place downtown?"},
      {"role": "user", "content": "I heard they have great cold brew"},
      {"role": "assistant", "content": "Yes! A few new spots opened up recently."}
    ],
    "placement": {"placement": "group_chat", "placement_id": "gc-main"},
    "viewers": [
      {
        "email_hash": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
        "device": {"ip": "1.2.3.4", "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0)", "country": "US"}
      },
      {
        "email_hash": "b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3",
        "device": {"ip": "5.6.7.8", "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)", "country": "US"}
      },
      {
        "email_hash": "c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4",
        "device": {"ip": "9.9.9.9", "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "country": "GB"}
      }
    ],
    "excludedTopics": ["gambling"],
    "relevancy": 0.3
  }'
Serve a single contextual ad to multiple users in a group chat. The engine runs one auction and generates one ad creative, then returns per-viewer impression and click URLs so each user’s engagement is individually tracked and billed.
Maximum 5 viewers per request. Each viewer gets a unique impUrl and clickUrl for individual attribution.

Headers

Authorization
string
required
Your Gravity API key. Format: Bearer <key>

Body

sessionId
string
required
Session identifier. Used for frequency capping and reporting. Typically the group chat ID.
messages
array
Conversation history from the group chat. Array of {role, content} message objects. The engine uses the last few messages for contextual matching.
placement
object
required
Single placement for the group chat ad slot.
FieldTypeDescription
placementstringPlacement type — use "group_chat".
placement_idstringYour slot identifier for this group chat.
viewers
array
required
Array of viewers in the group chat (1–5). Each viewer gets a unique impression/click URL in the response.
FieldTypeRequiredDescription
email_hashstringYesSHA-256 hex digest of the viewer’s email (email.strip().lower()). Must be exactly 64 characters.
userobjectNoUser context (same shape as the contextual endpoint user field).
deviceobjectNoDevice signals — ip, ua, country, etc. Used for bot detection and geo targeting per viewer.
metadata
object
Optional. Arbitrary metadata forwarded to the engine for targeting and analytics.
excludedTopics
array
Optional. Array of topic strings to exclude from matching.
relevancy
number
Optional. Minimum relevancy threshold, 0.0–1.0. Falls back to publisher baseline when omitted.
testAd
boolean
default:"false"
Optional. When true, returns test creative and skips billing/metrics.
curl -X POST https://server.trygravity.ai/api/v1/ad/group \
  -H "Authorization: Bearer <your_publisher_api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "sessionId": "group-chat-abc",
    "messages": [
      {"role": "user", "content": "has anyone tried that new coffee place downtown?"},
      {"role": "user", "content": "I heard they have great cold brew"},
      {"role": "assistant", "content": "Yes! A few new spots opened up recently."}
    ],
    "placement": {"placement": "group_chat", "placement_id": "gc-main"},
    "viewers": [
      {
        "email_hash": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
        "device": {"ip": "1.2.3.4", "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0)", "country": "US"}
      },
      {
        "email_hash": "b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3",
        "device": {"ip": "5.6.7.8", "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)", "country": "US"}
      },
      {
        "email_hash": "c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4",
        "device": {"ip": "9.9.9.9", "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "country": "GB"}
      }
    ],
    "excludedTopics": ["gambling"],
    "relevancy": 0.3
  }'

Response

On a successful match the endpoint returns HTTP 200 with a single ad object and per-viewer tracking URLs:
{
  "adText": "Keep your cold brew fresh with amika's insulated cooler bag.",
  "title": "amika Insulated Cooler Bag",
  "brandName": "Amika",
  "cta": "Shop Now",
  "url": "https://www.amika.com/",
  "favicon": "https://www.google.com/s2/favicons?domain=www.amika.com&sz=64",
  "viewers": [
    {
      "email_hash": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
      "impUrl": "https://api.trygravity.ai/ack?p=...",
      "clickUrl": "https://api.trygravity.ai/track/click?p=..."
    },
    {
      "email_hash": "b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3",
      "impUrl": "https://api.trygravity.ai/ack?p=...",
      "clickUrl": "https://api.trygravity.ai/track/click?p=..."
    },
    {
      "email_hash": "c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4",
      "impUrl": "https://api.trygravity.ai/ack?p=...",
      "clickUrl": "https://api.trygravity.ai/track/click?p=..."
    }
  ]
}

Response fields

FieldTypeDescription
adTextstringGenerated ad copy, contextually matched to the conversation
titlestringProduct/campaign title
brandNamestringAdvertiser brand name
ctastringCall to action text
urlstringLanding page URL
faviconstringBrand favicon URL
viewersarrayPer-viewer tracking URLs (see below)

Viewer tracking object

FieldTypeDescription
email_hashstringEchoes back the viewer’s email hash
impUrlstringImpression pixel URL — fire when the ad is visible to this viewer
clickUrlstringTracked click URL — use for ad links shown to this viewer
Null fields are omitted from the response.
Each viewer has their own impUrl and clickUrl. Fire the correct URL for each user — this is how per-viewer billing and attribution works. Do not reuse one viewer’s URLs for another.

How it works

  1. One auction — the conversation context goes through a single auction to find the best-matching campaign.
  2. One ad generation — a single ad creative is generated using the publisher’s configured prompt template and model.
  3. Per-viewer fan-out — each viewer gets a unique tracking URL pair (impUrl + clickUrl) with their own click ID (grclid). Bot viewers (detected by user agent) are excluded from the response.
  4. One engine event — a single engine event is logged with per-viewer data stored in the request context.

No ad available

When no ad matches the context (or the request times out, hits a bot filter for all viewers, or encounters an unrecoverable error), the endpoint returns HTTP 204 No Content with an empty body. Hide the ad slot in this case.