diff --git a/modules/ROOT/nav.adoc b/modules/ROOT/nav.adoc index 8edb393..8015112 100644 --- a/modules/ROOT/nav.adoc +++ b/modules/ROOT/nav.adoc @@ -5,6 +5,7 @@ * xref:page$other/v2_player_properties.adoc[Player Properties] * xref:page$rewards/endpoint.adoc[Teak Reward Endpoint] * xref:page$rewards/claiming.adoc[Claiming Teak Rewards] +* xref:page$other/v2_analytics_events.adoc[Analytics Events] * xref:page$other/v2_purchase.adoc[Purchase Reporting] * xref:page$other/v2_opt_out_categories.adoc[Opt Out Category Management] * xref:page$other/v2_email.adoc[Email Address Management] diff --git a/modules/ROOT/pages/other/v2_analytics_events.adoc b/modules/ROOT/pages/other/v2_analytics_events.adoc new file mode 100644 index 0000000..5b8c9eb --- /dev/null +++ b/modules/ROOT/pages/other/v2_analytics_events.adoc @@ -0,0 +1,239 @@ += Analytics Events + +Use this endpoint to send custom analytics events to Teak from your game server. Events submitted through this API are usable in segmentation the same way SDK-reported events are. + +This is primarily useful for game architectures where events are generated server-side and forwarded to third parties, rather than being generated by the game client. + +== Sending a Single Event +:endpoint: v2/analytics_events +:rate_limit: 100 +[cols="1h,3a", frame="none", grid="none"] +|=== +| Endpoint +| https://api.gocarrot.com/{endpoint} +| Request Type +| POST +| Content-Type +| application/json or application/x-www-form-urlencoded +| Rate Limiting +| {rate_limit} requests per second +|=== + +=== Required Parameters +[cols="1,3a", stripes="even"] +|=== +|Name | Description + +| game_id +| Your Teak App ID +| secret_key +| Your Teak Server Secret +| user_id +| The Game Assigned Player ID of the player this event is for. This must match the value provided by the game client's Teak SDK integration. +| action_type +| The event type string (e.g. "level_up", "purchase"). Corresponds to the `action_type` parameter in the SDK's `incrementEvent`. +|=== + +=== Optional Parameters +[cols="1,3a", stripes="even"] +|=== +|Name | Description + +| object_type +| The event category string (e.g. "character", "item"). Corresponds to the `object_type` parameter in the SDK's `incrementEvent`. +| object_instance_id +| Additional context for the event (e.g. "warrior", "sword"). Corresponds to the `object_instance_id` parameter in the SDK's `incrementEvent`. +| event_count +| The number of times this event occurred. Used for aggregate event reporting. Defaults to 1 if omitted. +| value +| An arbitrary numeric value associated with this event. For example, the total coin cost across all occurrences. Defaults to 1 if omitted. +| sum_of_squares +| The sum of squared per-occurrence values for this event. Used for statistical calculations (variance/standard deviation). Defaults to 1 if omitted. +| client_ip +| The player's IP address. Used for geographic segmentation. Takes highest priority for geo resolution. If both `client_ip` and `country_code` are provided, `client_ip` is used. +| country_code +| ISO 3166-1 alpha-2 country code for the player (e.g. "US", "GB"). Used for geographic segmentation when `client_ip` is not provided. If neither `client_ip` nor `country_code` is provided, the player's location from their most recent SDK session is used automatically. +|=== + +=== Success Response +[cols="1,3a"] +|=== +| Status Code +| 200 +| Response Body +| JSON dictionary. +[cols="1,3a", stripes="even"] +!=== +! status +! 'ok' +!=== +| Example +| [source, json] +---- +{ + "status": "ok" +} +---- +|=== + +=== Error Responses + +==== Not Found + +:response-code: 404 +:response-body: JSON dictionary with 'status' and 'errors' keys. 'status' will be 'error'. 'errors' will be a dictionary indicating which resource was not found. +:response-example: {"status":"error","errors":{"user_id":["could not be found"]}} +include::partial$response.adoc[] + +==== Rate Limit Response + +:response-code: 429 +:response-body: JSON dictionary with 'status' and 'errors' keys. 'status' will be 'rate_limit'. 'errors' will contain the key 'rate_limit' +:response-example: {"status":"rate_limit","errors":{"rate_limit":["/{endpoint} may only be called {rate_limit} times per second. Please wait a second and try again"]}} +include::partial$response.adoc[] + +== Batch Sending +:batch_endpoint: v2/analytics_events/batch +:batch_rate_limit: 100 +[cols="1h,3a", frame="none", grid="none"] +|=== +| Endpoint +| https://api.gocarrot.com/{batch_endpoint} +| Request Type +| POST +| Content-Type +| application/json or application/x-www-form-urlencoded +| Rate Limiting +| {batch_rate_limit} requests per second +| Batch Size +| Up to 100 events per request +|=== + +Use this endpoint to send multiple analytics events in a single request. This is more efficient than making individual requests when you need to report many events at once. + +=== Required Parameters +[cols="1,3a", stripes="even"] +|=== +|Name | Description + +| game_id +| Your Teak App ID +| secret_key +| Your Teak Server Secret +| events +| An array of event objects. Maximum of 100 events per request. +|=== + +=== Event Object Structure +[cols="1,3a", stripes="even"] +|=== +|Name | Description + +| user_id +| *Required.* The Game Assigned Player ID of the player this event is for. +| action_type +| *Required.* The event type string. +| object_type +| The event category string. +| object_instance_id +| Additional context for the event. +| event_count +| The number of times this event occurred. Defaults to 1 if omitted. +| value +| An arbitrary numeric value associated with this event. For example, the total coin cost across all occurrences. Defaults to 1 if omitted. +| sum_of_squares +| The sum of squared per-occurrence values for this event. Defaults to 1 if omitted. +| client_ip +| The player's IP address for geographic segmentation. Takes highest priority for geo resolution. +| country_code +| ISO 3166-1 alpha-2 country code for geographic segmentation. Used when `client_ip` is not provided. Falls back to last SDK session location if neither is specified. +|=== + +=== Example Request +[source, json] +---- +{ + "game_id": "your_teak_app_id", + "secret_key": "your_server_secret", + "events": [ + { + "user_id": "player_123", + "action_type": "level_up", + "object_type": "character", + "object_instance_id": "warrior", + "event_count": 1 + }, + { + "user_id": "player_456", + "action_type": "spin", + "object_type": "Mr. Bling Bling's Slots", + "object_instance_id": "bet_5000", + "event_count": 10, + "value": 50000, + "sum_of_squares": 250000000, + "country_code": "US" + } + ] +} +---- + +In the second event, the player spun a slot machine ten times at 5,000 coins per spin. The `value` is the total coin cost (50,000) and `sum_of_squares` is 5000^2^ x 10 = 250,000,000. + +=== Success Response +[cols="1,3a"] +|=== +| Status Code +| 200 +| Response Body +| JSON dictionary. +[cols="1,3a", stripes="even"] +!=== +! status +! 'ok' +! results +! An array of result objects, one for each event in the request. Each result contains `status`, `user_id`, and optionally `errors`. +! summary +! A summary object with `total_events`, `successful_events`, and `failed_events` counts. +!=== +| Example +| [source, json] +---- +{ + "status": "ok", + "results": [ + { + "status": "ok", + "user_id": "player_123" + }, + { + "status": "error", + "user_id": "unknown_player", + "errors": {"user_id": ["could not be found"]} + } + ], + "summary": { + "total_events": 2, + "successful_events": 1, + "failed_events": 1 + } +} +---- +|=== + +NOTE: Individual event failures do not prevent other events in the batch from being processed. Check the `results` array to determine which events were processed successfully. + +=== Error Responses + +==== Bad Request + +:response-code: 400 +:response-body: JSON dictionary with 'status' and 'errors' keys. 'status' will be 'error'. 'errors' will contain validation errors for the request. +:response-example: {"status":"error","errors":{"events":["must be a non-empty array (max 100 items)"]}} +include::partial$response.adoc[] + +==== Rate Limit Response + +:response-code: 429 +:response-body: JSON dictionary with 'status' and 'errors' keys. 'status' will be 'rate_limit'. 'errors' will contain the key 'rate_limit' +:response-example: {"status":"rate_limit","errors":{"rate_limit":["/{batch_endpoint} may only be called {batch_rate_limit} times per second. Please wait a second and try again"]}} +include::partial$response.adoc[]