Overview

A single GraphQL endpoint that mirrors the core REST resources so callers can fetch exactly the fields they need in one round trip. Authentication, authorization, and the underlying Searchkick services are shared with the REST API, so a GraphQL query returns the same records the equivalent REST call would.

Endpoint

URL

POST /api/v1/graphql

Body: { "query": "…", "variables": {…}, "operationName": "…" }

Authentication

X-Api-Key: YOUR_API_KEY

Same as REST. Bearer (Auth0) is also accepted.

API Playground

Build and run GraphQL queries against your account in the browser. Requests use your API key when signed in. Sign in to enable live testing with your API key.

Response

Equivalent curl

Authentication

GraphQL uses the same credentials and rate-limits as the REST API. Send your key on every request:

curl -X POST https://app.hienergy.ai/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $ROCKET_API_KEY" \
  -d '{"query":"{ __typename }"}'

Missing or invalid credentials return 401 Unauthorized in the standard REST error envelope ({ error: { code, message, … } }) rather than the GraphQL errors array, so existing tooling that branches on HTTP status keeps working.

What's exposed

Run an __schema introspection query (or the "Schema introspection" example in the playground) for the full field/argument list. The core surface:

Single-record lookups

  • advertiser(id, slug)
  • deal(id)
  • transaction(id)
  • term(id)
  • publisher(id, slug)
  • network(id, slug)
  • tag(id, slug)
  • accountActivitySummary(id)

Paginated lists

All list fields return { nodes, pageInfo }. pageInfo always carries currentPage, perPage, nextPage, prevPage, and hasNextPage. totalCount / totalPages are only populated when includeTotal: true is requested (capped at 100,000).

  • advertisers(publisherId, networkId, status, query, …) — Searchkick-backed
  • deals(advertiserId, exclusive, featured, device, activeOn, includeHidden, …) — visible deals by default; opt in to hidden with includeHidden: true (full reference)
  • transactions(advertiserId, publisherId, networkId, startDate, endDate, status, …) — Searchkick-backed, bounded query required (full reference)
  • contacts(advertiserId, advertiserName, domain, email, query, …) — Searchkick-backed HiEnergy contacts, bounded query required (full reference)
  • contact(id) — single contact by id
  • clicks(startDate!, endDate!, publisherId, advertiserId, …) — Searchkick-backed, 90-day window (full reference)
  • terms(advertiserId, campaignId, query, …) — commission terms, paid-account scope (full reference)
  • publishers(query, …)
  • networks(active, …)
  • tags(query, …)
  • accountActivitySummaries(summaryDate, accountType, accountId, …) — paid accounts only

Resource references

Every resource below has an argument table, field list, and parity notes vs REST: Advertisers, Deals, Clicks, Transactions, Terms, Publishers / Networks / Tags, and Account activity summaries. New to the schema? Start with Writing queries and Types & scalars.

Writing queries

The endpoint accepts a JSON body with three keys: query (the GraphQL document, required), variables (a JSON object, optional), and operationName (required only when a document defines more than one operation). Everything is a query operation — the schema exposes no mutations or subscriptions.

Variables

Prefer variables over string interpolation so values are typed and escaped by the server. Declare them in the operation signature and pass them in the variables object.

{
  "query": "query Deals($advertiserId: ID, $limit: Int) { deals(advertiserId: $advertiserId, perPage: $limit) { nodes { id name } pageInfo { hasNextPage } } }",
  "variables": { "advertiserId": "123", "limit": 10 }
}

Aliases & multiple root fields

Fetch several resources in one round trip, and use aliases to disambiguate repeated fields.

query Dashboard($advertiserId: ID!, $from: IsoDate!, $to: IsoDate!) {
  advertiser(id: $advertiserId) { id name rocketScore }
  activeDeals: deals(advertiserId: $advertiserId) { pageInfo { totalCount } }
  clicks(startDate: $from, endDate: $to, advertiserId: $advertiserId) {
    nodes { clickDate clickCount }
  }
}

Fragments

Reuse a selection set across fields with a fragment.

query($advertiserId: ID) {
  deals(advertiserId: $advertiserId) { nodes { ...DealCard } }
}

fragment DealCard on Deal {
  id
  name
  exclusive
  advertiser { id name }
}

Only select what you need

Resolvers use lookahead: nested associations (e.g. advertiser, network, publisher) are only eager-loaded when your selection set includes them, so asking for { id } avoids the joins that { id advertiser { network { name } } } triggers. Deeper/wider selections also cost more against the depth (12) and complexity (5,000) budgets — see Errors & limits.

Types & scalars

Alongside the GraphQL built-ins (ID, String, Int, Float, Boolean), the schema defines a few custom scalars and enums. A trailing ! means non-null; [Type!] is a list.

Type Kind Description
IDscalarSerialized as a string. Numeric ids are returned as strings (e.g. "123"); most id arguments also accept a slug where noted.
IsoDatescalarISO-8601 calendar date YYYY-MM-DD. Invalid input returns a coercion error.
IsoTimescalarISO-8601 timestamp (date + time, UTC) for createdAt/updatedAt/window fields.
TransactionStatusenumPENDING, APPROVED, PAID, REJECTED.
*ConnectionobjectList wrapper: { nodes, pageInfo } (e.g. DealConnection, TransactionConnection).
PageInfoobjectPagination metadata — see Pagination & totals.

PageInfo fields

Field Type Description
currentPageIntThe page that was returned
perPageIntPage size in effect (after clamping)
nextPage, prevPageIntAdjacent page numbers, or null at the ends
hasNextPageBooleanAlways populated (n+1 lookahead)
totalCount, totalPagesIntOnly when includeTotal: true (capped at 100,000)

Advertisers

Look up a single advertiser with advertiser(id:, slug:) or search the paginated advertisers list. Search is served by the same Searchkick/Elasticsearch service as GET /api/v1/advertisers, and results are scoped by AdvertiserPolicy.

Queries

FieldArgumentsReturns
advertiser id: ID and/or slug: String (one required) Advertiser or null when not found or not authorized
advertisers See filters below + page, perPage, includeTotal AdvertiserConnection{ nodes, pageInfo }

List filters (advertisers)

ArgumentTypeDescription
queryStringFree-text name/domain search (Searchkick)
publisherIdIDRestrict to a publisher (admins; non-admins stay in scope)
networkIdIDRestrict to a network
statusStringAdvertiser status filter
page, perPage, includeTotalpaginationDefaults 1 / 25 (max 200) / false

Advertiser fields

Grouped for readability; run introspection for the exhaustive list.

GroupFields
Identityid, cid, name, displayName, slug, url, domain, description, status, programStatus, programDetails, closureDate, contactEmail
MediaiconUrl, logoUrl, largeLogoUrl
Relationshipsnetwork, networkId, networkName, publisher, publisherId, publisherName, masterAdvertiserId
CommissioncommissionRate, averageCommissionRate, defaultCommissionRate, maxCommissionRate, minCommissionRate, medianCommissionRate, networkDefaultCommission, networkMaxCommission, networkMinCommission, commissionSummary, flatRateCommissionCents, flatRateCommissionCurrency, exclusionsDescription
CountstransactionsCount, campaignsCount, contactsCount, statusChangesCount, termsCount, dealsCount
MetricstotalSales, totalCommissions, estimatedGrossRevenue, estimatedSalesYearly, estimatedPageViews, trustPilotReviewCount, trustPilotAverageRating, rocketScore, rankPercentile, pageViewPercentile, revenuePercentile
SociallinkedinUrl, facebookUrl, twitterUrl, instagramUrl, pinterestUrl, youtubeUrl
Taxonomy listscountryList, verticalList, domainList, vibeList, demographicList, seasonList, riskList
TimestampslastNetworkSyncAt, createdAt, updatedAt

Deals

Query affiliate deals through deal(id) or the paginated deals list. Both use Pundit DealPolicy scopes, matching GET /api/v1/deals.

Hidden deals are opt-in: the deals list defaults to hidden: false (same as REST GET /api/v1/deals). To include hidden deals you are authorized to see, pass includeHidden: true — results stay scoped by DealPolicy either way. deal(id:) returns a hidden deal directly when your API key is allowed to see it.

Queries

Field Arguments Returns
deal id: ID! Deal or null when not found or not authorized
deals See filter table below + page, perPage, includeTotal DealConnection{ nodes, pageInfo }

List filters (deals)

Argument Type Description
advertiserId ID Restrict to one advertiser
exclusive Boolean Exact match on exclusive flag
featured Boolean Exact match on featured flag
device String Exact device targeting match: all, desktop, mobile, or tablet
activeOn IsoDate Deals effective on/before end-of-day and not expired before start-of-day
includeHidden Boolean Include deals flagged hidden. Defaults to false (hidden deals omitted). When true, hidden deals the caller can access are returned alongside visible ones.
page Int Page number (default 1)
perPage Int Page size (default 25, max 200)
includeTotal Boolean When true, populates pageInfo.totalCount (capped at 100,000)

Deal fields

Field Type Description
idID!Deal ID
name, description, termsStringDeal copy
descriptionIntentionallyBlankBooleanEmpty description is intentional when true
link, codeStringTracking URL / promo code when present
exclusive, featured, hiddenBooleanDeal flags (deals list omits hidden deals unless includeHidden: true)
dealKindStringDeal kind / type label
deviceStringDevice targeting: all, desktop, mobile, or tablet
effectiveAt, expiresAtIsoTimeAvailability window
advertiserAdvertiserNested advertiser (loaded when selected)
advertiserId, campaignIdIDForeign keys
countries[String!]Country codes when scoped geographically
createdAt, updatedAtIsoTimeRecord timestamps

Clicks

Query daily advertiser click roll-ups through the paginated clicks field. Uses the same Searchkick-backed ClicksSearchkickService as GET /api/v1/clicks, with ClickPolicy#index? and post-load advertiser visibility filtering. There is no click(id) singleton (parity with REST).

Date window required: startDate and endDate are required, endDate must be ≥ startDate, and the inclusive range may not exceed 90 days. Filter by advertiserId and/or publisherId when you need a tighter slice.

Queries

Field Arguments Returns
clicks startDate!, endDate!, optional filters + pagination ClickConnection{ nodes, pageInfo }

List filters (clicks)

Argument Type Description
startDate, endDate IsoDate! Required inclusive click-date range (YYYY-MM-DD); max 90 days
advertiserId ID Numeric advertiser ID — applied in Searchkick and SQL fallback
publisherId ID Publisher scope (admins only; non-admins stay on visible publishers)
page Int Page number (default 1)
perPage Int Page size (default 25, max 200)
includeTotal Boolean When true, populates pageInfo.totalCount (capped at 100,000)

Click fields

Field Type Description
idID!Roll-up row ID
clickDateIsoDateUTC date of the aggregated clicks
clickCountIntNumber of clicks that day
advertiserId, advertiserName, advertiserSlugscalarsAdvertiser identity on the roll-up
publisherId, publisherNamescalarsPublisher identity (when in scope)
networkId, networkNamescalarsNetwork identity (loaded when selected)

Transactions

Query affiliate transactions through transaction(id) or the paginated transactions list. Both use the same Searchkick-backed TransactionsSearchkickService as GET /api/v1/transactions, with Pundit authorization applied after Searchkick returns matching IDs.

Bounded query required: pass at least one of advertiserId, publisherId, networkId, or both startDate and endDate. Explicit date windows cannot exceed 90 days. When dates are omitted but another bound is present, Elasticsearch is limited to the last 30 days. Unbounded transactions queries return a GraphQL validation error, and the resolver never falls back to scanning SQL.
REST vs GraphQL: GraphQL exposes the core transaction filters (date range, advertiser, publisher, network, status). Advanced REST-only filters such as q, sort_by, currency, campaign_id, and amount/rate ranges are not yet on the GraphQL transactions field — use REST when you need those.

Queries

Field Arguments Returns
transaction id: ID! Transaction or null when not found or not authorized
transactions See filter table below + page, perPage, includeTotal TransactionConnection{ nodes, pageInfo }

List filters (transactions)

Argument Type Description
advertiserId ID Numeric advertiser ID or slug
publisherId ID Publisher scope (admins only; non-admins are always scoped to visible publishers)
networkId ID Numeric network ID or slug
startDate, endDate IsoDate Inclusive transaction-date range (YYYY-MM-DD). Providing one without the other is invalid; both count as a query bound.
status [TransactionStatus!] One or more of PENDING, APPROVED, PAID, REJECTED
page Int Page number (default 1)
perPage Int Page size (default 25, max 200)
includeTotal Boolean When true, populates pageInfo.totalCount (capped at 100,000)

Transaction fields

Field Type Description
idID!Hi Energy transaction ID
cidStringNetwork-side transaction identifier
transactionDateIsoDateTransaction date
saleAmount, commissionAmountFloatDecimal amounts (not cents)
commissionRateFloatCommission rate percentage
currencyStringISO currency code
quantityIntLine-item quantity when reported by the network
statusTransactionStatus!Normalized lifecycle status
rawStatusStringOriginal status token from the network payload
statusSourceStringrawResponse field path used for normalization
statusTimestampsTransactionStatusTimestamps!Per-status timestamps and *Source provenance fields
advertiser, network, publishernested typesNested associations (loaded only when selected)
campaignIdIDLinked campaign ID when present
createdAt, updatedAtIsoTimeRecord timestamps

TransactionStatus enum

PENDING, APPROVED, PAID, REJECTED — derived from each network's rawResponse using the same normalization rules as the REST API.

statusTimestamps sources

  • sync_observed — Hi Energy saw the status transition during sync
  • backfill_network — date reported by the affiliate network in rawResponse
  • backfill_transaction_date, backfill_created_at, backfill_updated_at — best-effort historical inference

Contacts

Query HiEnergy marketing contacts through contact(id) or the paginated contacts list. Both use the same Searchkick-backed ContactSearchService as GET /api/v1/contacts, so list queries stay fast against millions of rows without falling back to SQL. Results always require rating >= 1. MCP-created contacts are stamped with source HiEnergy MCP (caller email) and lastEditedBy set to the authenticated MCP caller.

Bounded query required. Pass at least one of advertiserId, advertiserName, domain, email, or query. Unbounded contacts requests return a GraphQL error.
Field Purpose
contact(id) Single contact by id (null when missing / unauthorized)
contacts Paginated HiEnergy contacts (rating >= 1), ordered by rating then updatedAt

List filters

Argument Notes
advertiserIdHiEnergy advertiser id or slug
advertiserNameFree-text advertiser name match
domainAdvertiser domain (e.g. aloyoga.com)
emailExact email match
queryFree-text over name/email/title/LinkedIn
sourceExact contacts.source value (MCP creates use HiEnergy MCP (caller email))
hasLinkedinOnly contacts with a LinkedIn URL
includeUnverifiedInclude status unverified (default false); does not relax rating ≥ 1
page / perPage / includeTotalSame pagination contract as other list fields

Terms

Query AI-extracted advertiser commission terms through term(id) or the paginated terms list. Both use Pundit TermPolicy scopes.

Paid-account scope: terms are restricted to the caller's own paid publisher plus any agency-managed paid publishers (admins see all). Agency-only users receive an empty list. Results are ordered by createdAt desc.

Queries

Field Arguments Returns
term id: ID! Term or null when not found or not authorized
terms See filter table below + page, perPage, includeTotal TermConnection{ nodes, pageInfo }

List filters (terms)

Argument Type Description
advertiserId ID Restrict to one advertiser
campaignId ID Restrict to one campaign
query String Free-text filter matched against name, cid, and summary
page Int Page number (default 1)
perPage Int Page size (default 25, max 200)
includeTotal Boolean When true, populates pageInfo.totalCount (capped at 100,000)

Term fields

Field Type Description
idID!Terms record ID
cidStringNetwork-side identifier the terms were ingested under
nameStringTerms name/label
summaryStringAI-generated plain-language summary of the commission terms
advertiserAdvertiserNested advertiser (loaded when selected)
advertiserId, campaignIdIDForeign keys
createdAt, updatedAtIsoTimeRecord timestamps

Publishers, networks & tags

Reference resources for resolving ids and building filters. Publishers are scoped by PublisherPolicy (you see your own publisher plus any you manage; admins see all); networks and tags are global catalogs.

Queries

FieldArgumentsReturns
publisherid: ID and/or slug: StringPublisher or null
publishersquery: String + paginationPublisherConnection
networkid: ID and/or slug: StringNetwork or null
networksactive: Boolean + paginationNetworkConnection
tagid: ID and/or slug: StringTag or null
tagsquery: String + paginationTagConnection

Publisher fields

id, name, slug, domain, description
publisherType, companyType, headquarters
linkedinProfileUrl
network, networkId
hideDeals, linkGeneratorEnabled, applicationRequestsEnabled
lastPaidAt, createdAt, updatedAt

Network fields

id, name, slug
active, subaffiliate
createdAt, updatedAt

Tag fields

id, name, slug
taggingsCount
createdAt, updatedAt

Account activity summaries

Daily Markdown digests of the preceding 7 days for a publisher or agency, via accountActivitySummary(id) or the paginated accountActivitySummaries list. Scoped by AccountActivitySummaryPolicy to the caller's paid publishers and managed agencies.

Paid accounts only: free users receive an authorization error (403). Admins see all accounts.

Queries & filters

Field / ArgumentTypeDescription
accountActivitySummaryid: ID!One summary, or null
accountActivitySummariesfilters + paginationAccountActivitySummaryConnection
summaryDateIsoDateFilter to a single day
accountTypeStringPublisher or Agency
accountIdIDA publisher or agency id within your scope

AccountActivitySummary fields

FieldTypeDescription
idID!Summary ID
accountType, accountId, accountNamescalarsThe publisher or agency the digest is for
summaryDateIsoDate!Digest day
periodStart, periodEnd, generatedAtIsoTime!7-day window covered and when it was built
statusChangesText, performanceText, connectedNetworksText, commissionDropsText, keyPointsTextString!Individual Markdown sections
markdownString!Combined Markdown digest (sections + transactions, deals, recommendations)

Pagination & totals

Every list field accepts page, perPage, and includeTotal:

  • page defaults to 1.
  • perPage defaults to 25, clamped at 200.
  • includeTotal: true returns pageInfo.totalCount / totalPages. Off by default — counting on huge tables is slow.
  • pageInfo.hasNextPage is always populated (using the standard n+1 trick).
  • Hard cap: page * perPage must be ≤ 10,000. Use filters (date range, IDs) instead of deep paging.

Examples

1) Search advertisers by name with totals

curl -X POST https://app.hienergy.ai/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $ROCKET_API_KEY" \
  -d '{
    "query": "query($q: String) { advertisers(query: $q, perPage: 5, includeTotal: true) { nodes { id name domain network { name } } pageInfo { hasNextPage totalCount } } }",
    "variables": { "q": "nike" }
  }'

2) Visible deals for an advertiser

curl -X POST https://app.hienergy.ai/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $ROCKET_API_KEY" \
  -d '{
    "query": "query($advertiserId: ID) { deals(advertiserId: $advertiserId, perPage: 10, includeTotal: true) { nodes { id name exclusive featured effectiveAt expiresAt advertiser { id name } } pageInfo { totalCount hasNextPage } } }",
    "variables": { "advertiserId": "123" }
  }'

2b) Include hidden deals (opt-in)

curl -X POST https://app.hienergy.ai/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $ROCKET_API_KEY" \
  -d '{
    "query": "query($advertiserId: ID) { deals(advertiserId: $advertiserId, includeHidden: true, perPage: 10) { nodes { id name hidden } pageInfo { hasNextPage } } }",
    "variables": { "advertiserId": "123" }
  }'

3) Clicks for a 7-day window, filtered by advertiser

curl -X POST https://app.hienergy.ai/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $ROCKET_API_KEY" \
  -d '{
    "query": "query($from: IsoDate!, $to: IsoDate!, $advertiserId: ID) { clicks(startDate: $from, endDate: $to, advertiserId: $advertiserId, perPage: 50) { nodes { id clickDate clickCount advertiserName networkName } pageInfo { hasNextPage } } }",
    "variables": { "from": "2026-05-19", "to": "2026-05-26", "advertiserId": "123" }
  }'

4) Transactions for a date range, with normalized status

curl -X POST https://app.hienergy.ai/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $ROCKET_API_KEY" \
  -d '{
    "query": "query($from: IsoDate!, $to: IsoDate!) { transactions(startDate: $from, endDate: $to, perPage: 25) { nodes { id transactionDate saleAmount commissionAmount status rawStatus statusSource statusTimestamps { pendingAt approvedAt paidAt rejectedAt pendingAtSource } advertiser { id name } } pageInfo { hasNextPage } } }",
    "variables": { "from": "2026-04-01", "to": "2026-04-30" }
  }'

5) Filter transactions by normalized status

curl -X POST https://app.hienergy.ai/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $ROCKET_API_KEY" \
  -d '{
    "query": "query($from: IsoDate!, $to: IsoDate!, $statuses: [TransactionStatus!]) { transactions(startDate: $from, endDate: $to, status: $statuses, perPage: 25, includeTotal: true) { nodes { id status rawStatus } pageInfo { totalCount } } }",
    "variables": { "from": "2026-04-01", "to": "2026-04-30", "statuses": ["APPROVED", "PAID"] }
  }'

6) Fetch a single transaction by ID

curl -X POST https://app.hienergy.ai/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $ROCKET_API_KEY" \
  -d '{
    "query": "query($id: ID!) { transaction(id: $id) { id transactionDate saleAmount commissionAmount status rawStatus statusSource statusTimestamps { pendingAt approvedAt paidAt rejectedAt pendingAtSource } advertiser { id name } network { name } } }",
    "variables": { "id": "12345" }
  }'

7) Commission terms for an advertiser

curl -X POST https://app.hienergy.ai/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $ROCKET_API_KEY" \
  -d '{
    "query": "query($advertiserId: ID) { terms(advertiserId: $advertiserId, perPage: 10, includeTotal: true) { nodes { id cid name summary advertiser { id name } } pageInfo { totalCount hasNextPage } } }",
    "variables": { "advertiserId": "123" }
  }'

8) Look up a publisher and a network by slug

curl -X POST https://app.hienergy.ai/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $ROCKET_API_KEY" \
  -d '{
    "query": "{ publisher(slug: \"acme-media\") { id name network { id name } } network(slug: \"awin\") { id name active } }"
  }'

9) Account activity summary for a day

curl -X POST https://app.hienergy.ai/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $ROCKET_API_KEY" \
  -d '{
    "query": "query($day: IsoDate) { accountActivitySummaries(summaryDate: $day, perPage: 5) { nodes { id accountType accountName summaryDate markdown } pageInfo { hasNextPage } } }",
    "variables": { "day": "2026-07-14" }
  }'

10) Introspect the available query fields

curl -X POST https://app.hienergy.ai/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $ROCKET_API_KEY" \
  -d '{
    "query": "{ __schema { queryType { fields { name args { name type { name ofType { name } } } } } } }"
  }'

Errors & limits

Two error channels

Authentication failures short-circuit before GraphQL runs and return the standard REST error envelope with an HTTP error status — so status-code branching keeps working:

HTTP/1.1 401 Unauthorized
{ "error": { "code": "unauthorized", "message": "Missing or invalid credentials" } }

Validation / business errors (unbounded transactions, click window > 90 days, depth/complexity exceeded, search temporarily unavailable, coercion failures) follow the GraphQL convention: HTTP 200 with an errors array and data: null for the failed field.

HTTP/1.1 200 OK
{
  "data": null,
  "errors": [
    { "message": "Transactions require advertiserId, publisherId, networkId, or both startDate and endDate." }
  ]
}

Always check for a non-empty errors array even on a 200 response. A partial success (some fields resolved, others errored) returns both data and errors.

Limits

  • Query depth is capped at 12 for data queries. Introspection (__schema/__type) is exempt, so standard client/tooling introspection works.
  • Query complexity is capped at 5,000 (list fields weight 10; keep selections focused). Introspection fields don't count toward this budget.
  • Pagination depth (page * perPage) is capped at 10,000. Use filters (date range, ids) instead of deep paging.
  • Page size (perPage) is clamped to 200.
  • Reported totals are capped at 100,000 to keep counts bounded.
  • Rate limiting uses the same per-key limits and API-call accounting as the REST API; a GraphQL request counts as one API call.

Per-resource rules

  • Deals list returns visible deals only (hidden: false) by default, matching REST; pass includeHidden: true to include authorized hidden deals.
  • Clicks date range is required and limited to 90 days.
  • Transactions require at least one bound (advertiserId, publisherId, networkId, or both dates); explicit date windows are capped at 90 days, and omitted dates default to the last 30 days in Elasticsearch.
  • Terms and account activity summaries require paid-account access; free/agency-only users may receive an empty list or a 403.
Ask Dex AIIntegration help

If this page feels TLDR, ask Dex AI.

Dex AI speaks your language, and all the other languages you may not. It will write the integration for you with the right endpoint and headers in one plain-English answer.