DYMOL
API REFERENCE v1.0.0

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.

Header
Authorization: Bearer dymol_sk_...

2 Base URL

All endpoints are relative to this base URL. Replace YOUR_PROJECT with your project slug.

Base URL
https://api.dymol.dev/v1

3 Error Handling

401 Unauthorized

Missing or invalid API key

403 Forbidden

Key not bound to a project

400 Bad Request

Missing required fields

404 Not Found

Resource doesn't exist

Error Response Format
{
  "error": "Unauthorized: Invalid API Key"
}

ReactionAPI

Sentiment-as-a-Service

Quick Start

using UnityEngine.Networking
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.

Request Body
{
  "target_id": "level_99",
  "type": "fire",
  "user_id": "player_123"
}
target_id string

The ID of the target (level, post, item)

type string

Reaction type e.g. fire, like, heart

user_id string

Unique player identifier

GET /v1/reactions

Get a global aggregation of all reactions, broken down by target_id.

Response
{
  "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.Networking
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.

Request Body
{
  "code_id": "SUMMER2025",
  "user_id": "player_123"
}
code_id string

The promo code to redeem (case-insensitive)

user_id string

Unique player identifier (prevents duplicate redemptions)

SUCCESS Response
{
  "status": "SUCCESS",
  "message": "Promo code redeemed successfully",
  "data": {
    "code_id": "SUMMER2025",
    "claims_count": 42,
    "max_claims": 1000
  }
}
ALREADY_CLAIMED Response
{
  "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.Networking
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.

Request Body
{
  "target_id": "boss_dragon_defeated",
  "user_id": "player_123",
  "amount": 1
}
target_id string, required

The ID of the event to count (e.g. "blocks_broken", "level_started")

user_id string, optional

Unique player identifier (logged for analytics)

amount integer, optional

Amount to increment by (default 1, max 1,000,000)

Response
{
  "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.

Response
{
  "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.

Response
{
  "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.

Response
{
  "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.Networking
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.

Request Body
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.

Request Body
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.

Request Body
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.

Response
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"
  }
}
COMING SOON

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.