Skip to content

Event ingress

Event ingress takes signups, purchases, refunds, and email addresses from your own server. ChannelGraph then credits the Content that brought each buyer in.

POST https://app.channelgraph.io/api/v1/ingress/events

Your server signs each call with a Workspace key.

  1. In ChannelGraph, open Settings, then API.
  2. Enter a name for the key, such as the name of your server, and click Create.
  3. Copy the key. ChannelGraph shows it once and never again.

A key starts with cgk_. It belongs to one Workspace, and every event it sends goes to that Workspace. Each member of the Workspace can create and revoke keys. A Workspace holds up to 50 keys that are not revoked.

Send the key in the Authorization header:

Authorization: Bearer cgk_...

Keep the key on your server. Never put it in a web page or an app. When a key leaks, revoke it on the same screen and create a new one.

Terminal window
curl https://app.channelgraph.io/api/v1/ingress/events \
-H "Authorization: Bearer $CHANNELGRAPH_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "purchase",
"offer_id": "p4c6e8g0j2l4n6q8",
"email": "buyer@example.com",
"order_id": "1001",
"amount": "49.00",
"currency": "USD"
}'

Response 202:

{ "event_id": "purchase:order:p4c6e8g0j2l4n6q8:1001" }

A 202 means that ChannelGraph stored the event. Do not send it again.

An Offer’s ID is the last part of the address of its page in ChannelGraph.

Type What it records Needs
signup A signup for an Offer. offer_id
purchase A purchase of an Offer. offer_id
refund A full or a partial refund of a purchase. offer_id and order_id
identify An email address for a browser or a click. It records no conversion. email

A signup or a purchase also needs email or token, or ChannelGraph cannot tell who converted. A purchase with an order_id is the one exception. ChannelGraph records it even without email or token.

Field Type Limit Meaning
type string signup, purchase, refund, or identify. Required. Case does not matter.
event_id string 1 to 64 characters Your own ID for the event. See idempotency.
offer_id string 32 characters The ID of an Offer in the Workspace. Required for signup, purchase, and refund.
email string 320 characters The person’s email address. Required for identify.
order_id string 200 characters The order or payment ID from your checkout. Required for refund.
amount string or number 32 characters The amount in major units, such as "49.99". Zero or more.
currency string 3 letters The currency code, such as USD. Case does not matter.
ts string 64 characters When the event happened, in ISO 8601, such as 2026-01-31T12:00:00Z.
token string 64 characters The cg_ or cv_ value that the page or the checkout carried. See tokens.
  • A time without an offset is in UTC.
  • Without ts, the event takes the time it arrived.
  • ts must be no more than 400 days in the past and no more than one hour in the future.
  • ChannelGraph ignores a field that it does not know. Thus a sender keeps working when a new version adds a field.

A token ties an event to the click or the browser that brought the person in.

Token Comes from
cg_ followed by 16 characters A ChannelGraph Link. The Link adds utm_content=cg_... to the address it opens.
cv_ followed by 22 characters The ChannelGraph snippet on your site. The snippet adds it to the checkout links on the page.

The snippet puts the cv_ value into these checkout fields:

Checkout Field
Stripe Payment Links client_reference_id
Lemon Squeezy checkout[custom][cg]
ThriveCart passthrough[cg]

Read the value back from the order, and send it as token. For example, read client_reference_id from the Stripe Checkout Session.

ChannelGraph uses a cg_ click only when the click belongs to your Workspace. It uses a cv_ browser only when your Workspace has seen the browser. Any other non-empty token fails with 422.

  • Send every amount in major units, such as "49.99", never in cents.
  • Send the amount as a string to keep its exact digits.
  • An amount without currency takes the currency of the Offer’s price. With no price either, the purchase has no amount.
  • An amount above 1,000,000 counts as no amount.
  • A purchase with no usable amount counts the Offer’s price.
  • A refund without an amount refunds the whole purchase.
  • A refund in another currency than its purchase does not change the purchase.
  • Refunds never take back more than the purchase counts.

ChannelGraph stores each event once. A retry of a stored event answers 202 with the same event_id and records nothing new.

An event’s ID comes from the first rule that applies:

Event ID
Any event with event_id Your event_id.
A refund with order_id refund:order:<offer_id>:<order_id>:<amount>. Without an amount, the last part is full.
Any other event with order_id <type>:order:<offer_id>:<order_id>.
Any other event <type>:sha256:<hash>. The hash covers the fields you sent and the event’s time.

Thus an order_id makes a retry safe without an event_id. An event with no event_id, no order_id, and no ts takes a new time on each call. Each such call is a new event.

Two partial refunds of the same amount on one order get the same derived ID. ChannelGraph then stores the second one as a retry of the first. Send a distinct event_id for each refund, such as the refund ID from your checkout.

Event ingress and the Automation API share one event ID space in each Workspace.

ChannelGraph also counts each conversion once:

  • A purchase with order_id counts once for each order of each Offer.
  • A purchase without order_id counts at most once for each person, Offer, and UTC day.
  • A signup counts once for each person and Offer.

A signup:

Terminal window
curl https://app.channelgraph.io/api/v1/ingress/events \
-H "Authorization: Bearer $CHANNELGRAPH_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "signup",
"offer_id": "a1b2c3d4e5f6g7h8",
"email": "reader@example.com",
"token": "cg_Ab3dE5gH7jK9mN1p"
}'

A partial refund:

Terminal window
curl https://app.channelgraph.io/api/v1/ingress/events \
-H "Authorization: Bearer $CHANNELGRAPH_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "refund",
"event_id": "re_3PqR8s",
"offer_id": "p4c6e8g0j2l4n6q8",
"order_id": "1001",
"amount": "19.00",
"currency": "USD"
}'

An email address for a browser:

Terminal window
curl https://app.channelgraph.io/api/v1/ingress/events \
-H "Authorization: Bearer $CHANNELGRAPH_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "identify",
"email": "reader@example.com",
"token": "cv_Xq3v9LmA0bC1dE2fG3hI4j"
}'

An error body has a detail string that names the problem.

{ "detail": "order_id: a refund names the order it reverses." }
Status Meaning
401 The key is missing, unknown, or revoked. detail is Send a live key as Authorization: Bearer cgk_....
413 The body is larger than 16 KiB.
422 The event is not valid. detail names the field, such as email: this is not an email address.
429 The key sent more than 600 events in this minute. Wait for the next minute, then send again.

A 422 also covers a body that is not a JSON object. Do not retry a 401, 413, or 422 without a change.

Limit Value
Events for each key 600 a minute
Body size 16 KiB
Keys that are not revoked in one Workspace 50