API Reference
Build game backend features in minutes. Our APIs are designed for indie developers who want production-grade infrastructure without the complexity.
1 Authentication
All API requests require a valid API key from your DYMOL Dashboard. Pass it in the Authorization header.
Authorization: Bearer dymol_sk_... 2 Base URL
All endpoints are relative to this base URL. Replace YOUR_PROJECT with your project slug.
https://api.dymol.dev/v1 3 Error Handling
Missing or invalid API key
Key not bound to a project
Missing required fields
Resource doesn't exist
{
"error": "Unauthorized: Invalid API Key"
} ReactionAPI
Sentiment-as-a-Service
Quick Start
using UnityEngine;
using UnityEngine.Networking;
using System.Text;
using System.Collections;
public class DymolReactions : MonoBehaviour {
private string apiKey = "YOUR_API_KEY";
public IEnumerator AddReaction(string targetId, string type, string userId) {
string url = "https://api.dymol.dev/v1/react";
string json = $"{{\"target_id\":\"{targetId}\",\"type\":\"{type}\",\"user_id\":\"{userId}\"}}";
using (UnityWebRequest www = new UnityWebRequest(url, "POST")) {
byte[] bodyRaw = Encoding.UTF8.GetBytes(json);
www.uploadHandler = new UploadHandlerRaw(bodyRaw);
www.downloadHandler = new DownloadHandlerBuffer();
www.SetRequestHeader("Content-Type", "application/json");
www.SetRequestHeader("Authorization", $"Bearer {apiKey}");
yield return www.SendWebRequest();
}
}
} POST /v1/react
Submit or update a reaction. Uses upsert — if the same user reacts again to the same target, their previous reaction is overwritten.
{
"target_id": "level_99",
"type": "fire",
"user_id": "player_123"
} The ID of the target (level, post, item)
Reaction type e.g. fire, like, heart
Unique player identifier
GET /v1/reactions
Get a global aggregation of all reactions, broken down by target_id.
{
"success": true,
"data": {
"total_reactions": 3,
"global_distribution": {
"fire": 2,
"heart": 1
},
"targets": {
"level_99": { "fire": 1 },
"junk_20": { "fire": 1, "heart": 1 }
}
}
} PromoCode API
Create limited promo codes for in-game rewards
Quick Start
using UnityEngine;
using UnityEngine.Networking;
using System.Text;
using System.Collections;
public class DymolPromoCodes : MonoBehaviour {
private string apiKey = "YOUR_API_KEY";
public IEnumerator RedeemPromoCode(string codeId, string userId) {
string url = "https://api.dymol.dev/v1/promo/redeem";
string json = $"{{\"code_id\":\"{codeId}\",\"user_id\":\"{userId}\"}}";
using (UnityWebRequest www = new UnityWebRequest(url, "POST")) {
byte[] bodyRaw = Encoding.UTF8.GetBytes(json);
www.uploadHandler = new UploadHandlerRaw(bodyRaw);
www.downloadHandler = new DownloadHandlerBuffer();
www.SetRequestHeader("Content-Type", "application/json");
www.SetRequestHeader("Authorization", $"Bearer {apiKey}");
yield return www.SendWebRequest();
if (www.result == UnityWebRequest.Result.Success) {
string response = www.downloadHandler.text;
Debug.Log("Promo response: " + response);
} else {
Debug.LogError("Promo error: " + www.error);
}
}
}
} POST /v1/promo/redeem
Redeem a promo code for a specific user. Each user can only redeem a code once. The code is automatically deactivated when claims_count reaches max_claims. The request is scoped to the project associated with the API key.
{
"code_id": "SUMMER2025",
"user_id": "player_123"
} The promo code to redeem (case-insensitive)
Unique player identifier (prevents duplicate redemptions)
{
"status": "SUCCESS",
"message": "Promo code redeemed successfully",
"data": {
"code_id": "SUMMER2025",
"claims_count": 42,
"max_claims": 1000
}
} {
"status": "ALREADY_CLAIMED",
"error": "You have already redeemed this code"
} Status Codes
SUCCESS — Code redeemed, reward granted
ALREADY_CLAIMED — This user already redeemed this code
EXHAUSTED — Code reached max claims or was deactivated
INVALID — Code does not exist in this project
CounterAPI
Track any in-game event with automatic aggregation
Quick Start
using UnityEngine;
using UnityEngine.Networking;
using System.Text;
using System.Collections;
public class DymolCounters : MonoBehaviour {
private string apiKey = "YOUR_API_KEY";
public IEnumerator IncrementCounter(string targetId, string userId, int amount = 1) {
string url = "https://api.dymol.dev/v1/counter/increment";
string json = $"{{\"target_id\":\"{targetId}\",\"user_id\":\"{userId}\",\"amount\":{amount}}}";
using (UnityWebRequest www = new UnityWebRequest(url, "POST")) {
byte[] bodyRaw = Encoding.UTF8.GetBytes(json);
www.uploadHandler = new UploadHandlerRaw(bodyRaw);
www.downloadHandler = new DownloadHandlerBuffer();
www.SetRequestHeader("Content-Type", "application/json");
www.SetRequestHeader("Authorization", $"Bearer {apiKey}");
yield return www.SendWebRequest();
if (www.result == UnityWebRequest.Result.Success) {
Debug.Log("Counter incremented!");
}
}
}
} POST /v1/counter/increment
Increment a counter for a specific target. Uses upsert — if the target doesn't exist, it's created automatically. Each increment is logged for analytics.
{
"target_id": "boss_dragon_defeated",
"user_id": "player_123",
"amount": 1
} The ID of the event to count (e.g. "blocks_broken", "level_started")
Unique player identifier (logged for analytics)
Amount to increment by (default 1, max 1,000,000)
{
"success": true,
"message": "Counter incremented successfully",
"data": {
"target_id": "boss_dragon_defeated",
"count": 1542
}
} GET /v1/counter
Get aggregated counters for all targets in your project, plus the global total.
{
"success": true,
"data": {
"total_counts": 15420,
"targets": {
"blocks_broken": 8400,
"boss_dragon_defeated": 1542,
"level_started": 5478
}
}
} GET /v1/counter/:target_id
Get the current count for a specific target.
{
"success": true,
"data": {
"target_id": "boss_dragon_defeated",
"count": 1542
}
} GET /v1/counter/daily
Get daily aggregated counter data for the last 7 days (or specify days query param). Optionally filter by target_id.
{
"success": true,
"data": [
{ "day": "2026-05-04", "count": 120 },
{ "day": "2026-05-05", "count": 245 },
{ "day": "2026-05-06", "count": 189 },
{ "day": "2026-05-07", "count": 312 },
{ "day": "2026-05-08", "count": 278 },
{ "day": "2026-05-09", "count": 401 },
{ "day": "2026-05-10", "count": 156 }
]
} PlaytimeAPI
Track how long players play, when they return, and which sessions keep them engaged.
Privacy: Use anonymous or pseudonymous player IDs. Do not send emails, real names, or personal data as user_id.
Quick Start
Start a session when gameplay begins, heartbeat every 60 seconds, and end the session when the game closes or pauses.
using UnityEngine;
using UnityEngine.Networking;
using System.Text;
using System.Collections;
public class DymolPlaytime : MonoBehaviour {
private string apiKey = "YOUR_API_KEY";
private string sessionId;
public IEnumerator StartSession(string userId) {
string json = $"{{\"user_id\":\"{userId}\"}}";
using (UnityWebRequest www = new UnityWebRequest("https://api.dymol.dev/v1/playtime/session/start", "POST")) {
byte[] bodyRaw = Encoding.UTF8.GetBytes(json);
www.uploadHandler = new UploadHandlerRaw(bodyRaw);
www.downloadHandler = new DownloadHandlerBuffer();
www.SetRequestHeader("Content-Type", "application/json");
www.SetRequestHeader("Authorization", $"Bearer {apiKey}");
yield return www.SendWebRequest();
if (www.result == UnityWebRequest.Result.Success) {
var response = JsonUtility.FromJson(www.downloadHandler.text, typeof(StartResponse));
sessionId = ((StartResponse)response).data.session_id;
InvokeRepeating("Heartbeat", 60f, 60f);
}
}
}
IEnumerator Heartbeat() {
string json = $"{{\"session_id\":\"{sessionId}\"}}";
using (UnityWebRequest www = new UnityWebRequest("https://api.dymol.dev/v1/playtime/session/heartbeat", "POST")) {
byte[] bodyRaw = Encoding.UTF8.GetBytes(json);
www.uploadHandler = new UploadHandlerRaw(bodyRaw);
www.downloadHandler = new DownloadHandlerBuffer();
www.SetRequestHeader("Content-Type", "application/json");
www.SetRequestHeader("Authorization", $"Bearer {apiKey}");
yield return www.SendWebRequest();
}
}
public IEnumerator EndSession() {
CancelInvoke("Heartbeat");
string json = $"{{\"session_id\":\"{sessionId}\"}}";
using (UnityWebRequest www = new UnityWebRequest("https://api.dymol.dev/v1/playtime/session/end", "POST")) {
byte[] bodyRaw = Encoding.UTF8.GetBytes(json);
www.uploadHandler = new UploadHandlerRaw(bodyRaw);
www.downloadHandler = new DownloadHandlerBuffer();
www.SetRequestHeader("Content-Type", "application/json");
www.SetRequestHeader("Authorization", $"Bearer {apiKey}");
yield return www.SendWebRequest();
}
}
[System.Serializable] private class StartResponse { public Data data; }
[System.Serializable] private class Data { public string session_id; public string user_id; public string started_at; }
void OnApplicationQuit() { StartCoroutine(EndSession()); }
} Session Lifecycle
1. Start — Call POST /v1/playtime/session/start when the game starts or player enters gameplay. You receive a session_id.
2. Heartbeat — Call POST /v1/playtime/session/heartbeat every 60 seconds while the session is active. This keeps the session alive and tracks duration.
3. End — Call POST /v1/playtime/session/end when the game closes, pauses, or returns to menu.
Crash recovery: If your game crashes without calling /end, DYMOL will use the last heartbeat timestamp for analytics. Sessions without heartbeats for 2 minutes are considered inactive. Maximum session duration is capped at 12 hours.
POST /v1/playtime/session/start
Start a new play session for a player.
POST https://api.dymol.dev/v1/playtime/session/start
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY
{
"user_id": "player_123"
}
// Response 200
{
"success": true,
"data": {
"session_id": "sess_abc123",
"user_id": "player_123",
"started_at": "2026-05-26T10:00:00Z"
}
} POST /v1/playtime/session/heartbeat
Update the last heartbeat for an active session. Recommended every 60 seconds.
POST https://api.dymol.dev/v1/playtime/session/heartbeat
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY
{
"session_id": "sess_abc123"
}
// Response 200
{
"success": true,
"data": {
"session_id": "sess_abc123",
"duration_seconds": 120,
"last_heartbeat_at": "2026-05-26T10:02:00Z"
}
} POST /v1/playtime/session/end
End an active session and finalize its duration.
POST https://api.dymol.dev/v1/playtime/session/end
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY
{
"session_id": "sess_abc123"
}
// Response 200
{
"success": true,
"data": {
"session_id": "sess_abc123",
"duration_seconds": 1840,
"ended_at": "2026-05-26T10:30:40Z"
}
} GET /v1/playtime/player/:user_id
Get playtime summary for a specific player across all sessions.
GET https://api.dymol.dev/v1/playtime/player/player_123
Authorization: Bearer YOUR_API_KEY
// Response 200
{
"success": true,
"data": {
"user_id": "player_123",
"total_playtime_seconds": 67320,
"playtime_30d_seconds": 15120,
"sessions_count": 49,
"average_session_seconds": 1373,
"longest_session_seconds": 3900,
"first_seen": "2026-05-01T09:00:00Z",
"last_seen": "2026-05-26T18:41:00Z"
}
} Death Telemetry API is under development.
DeathAPI
Track player death coordinates for heatmap analysis
Record a player death with 3D coordinates. Use this from your game client every time a player dies.