Skip to content
The Public API is available on request. Email support@grona.ai to get access.

Send an event batch

POST
/v1/mobile/events
Code sample: curl
# The Grona SDK makes this call. Your code does not.
# The body is gzip-compressed JSON, so compress it before you send it.
gzip -c batch.json | curl https://api.grona.ai/v1/mobile/events \
-H 'Content-Type: application/json' \
-H 'Content-Encoding: gzip' \
--data-binary @-

Called by the Grona SDK, not by your code.

The body is gzip-compressed JSON (Content-Encoding: gzip) with at most 50 events and at most 64 KB before compression. The workspace key travels in the body. Grona deduplicates events on event_id and corrects device clock skew using the time it receives the batch minus sent_at.

How the SDK handles the response:

  • Any 2xx: removes the batch from its queue. The response body is ignored.
  • 429 and 503: honours Retry-After.
  • Any other 4xx: drops the batch.
  • Other failures: retries at most 3 times with exponential backoff and jitter.
Content-Encoding
required
string
Allowed value: gzip
Media typeapplication/json
object
schema
required
integer
Allowed value: 1
workspace
required
string
/^[A-Za-z0-9._:-]{1,128}$/
sent_at
required

Unix milliseconds, device clock.

integer
sdk_version
required
string
app_version
required
string
platform
required
string
os_version
required

On Android, the API level, such as 34.

integer
events
required
Array<object>
<= 50 items
object
event_id
required

Random UUID. Grona deduplicates on it.

string format: uuid
seq
required

Per-install counter, so gaps reveal lost events.

integer
type
required
string
Allowed values: eligible served anchor_visible exposure action dismiss view_item add_to_cart remove_from_cart begin_checkout purchase
trigger
required
string
Allowed values: decision render anchor_1s content_50pct_1s tap host_call host
ts
required

Unix milliseconds, device clock.

integer
session_id
required
string format: uuid
install_id
required

SDK-owned install id.

string format: uuid
customer_id

Opaque customer id, only when the shopper is identified. Never an email or a phone number.

string
config_version

The config the decision came from.

integer
preview

true while a preview pin is active. Excluded from analysis.

boolean
demo

true only in demo mode. Excluded from analysis.

boolean
campaign_id
string
variant_id
string
arm
string
Allowed values: treatment control holdout global_holdout
unit
string
Allowed values: install customer
placement
string
key
string
data

Type-specific fields, for example delivery and grant_jti on offer events, or order_id, total_minor, currency, campaign_product_ids and treatments on purchase.

object
key
additional properties
any

Example

{
"schema": 1,
"workspace": "acme-market",
"sent_at": 1761681600123,
"sdk_version": "0.1.0",
"app_version": "4.2.0 (420)",
"platform": "android",
"os_version": 34,
"events": [
{
"event_id": "0f6b1c5e-2d8a-4b7e-9a51-3c2e7d9f4a10",
"seq": 41,
"type": "eligible",
"trigger": "decision",
"ts": 1761681598410,
"session_id": "8c1d2e3f-4a5b-4c6d-8e7f-90a1b2c3d4e5",
"install_id": "5e4d3c2b-1a09-4f8e-8d7c-6b5a49382716",
"customer_id": "cus_7Hq2Lm9x",
"config_version": 12,
"campaign_id": "free-delivery-bar",
"variant_id": "progress-bar",
"arm": "treatment",
"unit": "install",
"placement": "home_top"
}
]
}

Too many requests. Retry with exponential backoff and jitter, and wait at least as long as Retry-After when it is present. Branch on the status code; the body is not guaranteed to use the error envelope.

Retry-After
string

How long to wait before retrying, in seconds or as an HTTP date.

Temporarily unavailable. Retry with exponential backoff and jitter, and wait at least as long as Retry-After when it is present. Branch on the status code; the body is not guaranteed to use the error envelope.

Retry-After
string

How long to wait before retrying, in seconds or as an HTTP date.

Accepted. The SDK removes the batch and ignores the body.

The SDK drops the batch.

The SDK retries at most 3 times with backoff.