# Autres jeux (API REST)

{% hint style="warning" %}
L'intégration API est réservée au **propriétaire** du serveur de jeux.
{% endhint %}

Si votre jeu n'a pas de plugin dédié, vous pouvez intégrer QuantumLogs via l'**API REST** directement. Cette méthode fonctionne avec n'importe quel langage de programmation.

## Endpoint

```
POST /logs
```

## Authentification

Envoyez votre clé API dans le header `Authorization` :

```
Authorization: votre-cle-api-ici
```

{% hint style="info" %}
La clé est envoyée **directement** dans le header, sans préfixe `Bearer`. C'est le format attendu par QuantumLogs.
{% endhint %}

## Format de la requête

Le body est un **tableau JSON** de logs. Chaque élément du tableau est un objet log :

```json
[
  {
    "measurement": "player_kill",
    "timestamp": "2025-01-15T14:30:45.123Z",
    "tags": {
      "player_name": "John",
      "player_id": "12345",
      "player_global_id": "76561198000000000",
      "target_name": "Jane",
      "target_id": "67890",
      "target_global_id": "76561198000000001",
      "server": "serveur-1"
    },
    "fields": {
      "value": "John a tué Jane avec AK-47 à 50m (headshot)"
    },
    "metadata": {
      "weapon": "AK-47",
      "distance": 50,
      "bodypart": "head"
    }
  }
]
```

## Champs détaillés

### Champs obligatoires

| Champ          | Type              | Description                                                              |
| -------------- | ----------------- | ------------------------------------------------------------------------ |
| `measurement`  | string            | Type/catégorie du log (ex: `kill`, `chat`, `connect`)                    |
| `timestamp`    | string (ISO 8601) | Horodatage du log (ex: `2025-01-15T14:30:45.123Z`)                       |
| `fields`       | object            | Objet contenant le champ `value`                                         |
| `fields.value` | string            | Contenu textuel du log (c'est ce qui s'affiche dans la colonne "Valeur") |
| `tags`         | object            | Objet contenant les tags d'indexation (peut être vide `{}`)              |

{% hint style="danger" %}
Tous ces champs sont **obligatoires**. L'objet `tags` doit être présent même s'il est vide (`{}`). Le `timestamp` doit être au format ISO 8601 — il n'y a pas de valeur par défaut côté serveur.
{% endhint %}

### Tags reconnus par le backend

{% hint style="danger" %}
**Seuls les noms de tags listés ci-dessous sont reconnus.** Tout tag avec un nom différent sera **silencieusement ignoré** et n'apparaîtra pas dans vos logs. C'est la cause la plus fréquente de "logs qui ne fonctionnent pas".
{% endhint %}

| Tag                | Type   | Description                                                   |
| ------------------ | ------ | ------------------------------------------------------------- |
| `player_name`      | string | Nom du joueur                                                 |
| `player_id`        | string | ID du joueur (spécifique au serveur, ex: ID de personnage)    |
| `player_global_id` | string | Identifiant unique global du joueur (Steam ID 64, UUID, etc.) |
| `player_steamid`   | string | Steam ID (déprécié, utilisez `player_global_id`)              |
| `target_name`      | string | Nom de la cible                                               |
| `target_id`        | string | ID de la cible                                                |
| `target_global_id` | string | Identifiant unique global de la cible                         |
| `target_steamid`   | string | Steam ID de la cible (déprécié)                               |
| `server`           | string | Identifiant du serveur source                                 |

Tous les tags sont **optionnels**, mais `server` est **fortement recommandé** — il est utilisé pour le comptage de serveurs actifs et le contrôle des limites de votre plan.

**Exemples de tags invalides** (seront ignorés) :

* `weapon`, `distance`, `map` → Mettez ces infos dans `fields.value` ou dans `metadata`
* `attacker_name`, `victim_name` → Utilisez `player_name` et `target_name`
* `admin_name` → Utilisez `player_name`

### Champs optionnels

| Champ      | Type   | Description                                                                        |
| ---------- | ------ | ---------------------------------------------------------------------------------- |
| `metadata` | object | Données JSON supplémentaires libres (visible dans le détail du log, non filtrable) |

## Codes de réponse

### Succès

| Code    | Body | Description                       |
| ------- | ---- | --------------------------------- |
| **201** | `OK` | Logs reçus et insérés avec succès |

### Erreurs

| Code    | Description                   | Détail                                                                                                                      |
| ------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| **401** | Clé API invalide ou manquante | `{ "statusCode": 401, "message": "Missing authorization header" }` ou `{ "statusCode": 401, "message": "Invalid API key" }` |
| **413** | Body trop volumineux          | La taille maximale du body est de **50 Mo**                                                                                 |
| **429** | Limite de serveurs dépassée   | Voir détail ci-dessous                                                                                                      |
| **500** | Erreur serveur                | Injection bloquée (plan expiré/suspendu) ou erreur de base de données                                                       |

#### Détail de la réponse 429

Si vous dépassez le nombre de serveurs autorisés par votre plan, la réponse contient des informations utiles :

```json
{
  "statusCode": 429,
  "error": "Server Limit Exceeded",
  "message": "You have reached your server limit (5). Upgrade your plan to add more servers.",
  "upgradeUrl": "https://quantumlogs.com/pricing",
  "activeServers": ["rp-1", "rp-2", "pvp-1", "event-1", "test"],
  "maxServers": 5
}
```

{% hint style="info" %}
Les serveurs actifs sont suivis pendant **24 heures**. Un serveur qui n'envoie plus de logs pendant 24h libère automatiquement une place.
{% endhint %}

## Bonnes pratiques

### Envoi par lots

Envoyez vos logs **par lots** plutôt qu'un par un. Un intervalle de **10 secondes** est recommandé :

1. Accumulez les logs dans une file d'attente en mémoire
2. Toutes les 10 secondes, envoyez le lot complet en une seule requête
3. Videz la file après un envoi réussi

### Tout dans `fields.value`

Le champ `value` est le contenu principal de votre log. **Mettez-y toutes les informations lisibles**. Les `tags` ne servent qu'à l'indexation (recherche par joueur, serveur, etc.).

```json
// CORRECT - toutes les infos dans value
{
  "measurement": "player_kill",
  "timestamp": "2025-01-15T14:30:45.123Z",
  "fields": { "value": "John a tué Jane avec AK-47 à 50m (headshot)" },
  "tags": { "player_name": "John", "target_name": "Jane", "server": "rp-1" }
}
```

```json
// INCORRECT - les données custom dans les tags sont ignorées
{
  "measurement": "player_kill",
  "timestamp": "2025-01-15T14:30:45.123Z",
  "tags": { "weapon": "AK-47", "distance": "50", "bodypart": "head" },
  "fields": { "value": "" }
}
```

### Metadata pour les données structurées

Si vous avez besoin de stocker des données structurées en plus du texte, utilisez `metadata` :

```json
{
  "measurement": "player_kill",
  "timestamp": "2025-01-15T14:30:45.123Z",
  "fields": { "value": "John a tué Jane avec AK-47 à 50m (headshot)" },
  "tags": { "player_name": "John", "target_name": "Jane", "server": "rp-1" },
  "metadata": {
    "weapon": "AK-47",
    "distance": 50,
    "bodypart": "head",
    "position": { "x": 1234.5, "y": -567.89, "z": 100.23 }
  }
}
```

Les métadonnées sont stockées en JSON et visibles dans le détail du log, mais ne sont pas filtrables via les filtres classiques.

### Gestion des erreurs

* En cas d'erreur réseau, conservez les logs en mémoire et réessayez
* Implémentez un **retry** avec backoff exponentiel
* Envoyez les logs restants à l'arrêt du serveur (flush)

## Exemples

### cURL

```bash
curl -X POST https://votre-instance.quantumlogs.cloud/logs \
  -H "Content-Type: application/json" \
  -H "Authorization: votre-cle-api" \
  -d '[{
    "measurement": "test",
    "timestamp": "'$(date -u +%Y-%m-%dT%H:%M:%S.000Z)'",
    "fields": { "value": "Log de test depuis cURL" },
    "tags": { "server": "test-server" }
  }]'
```

### Python

```python
import requests
import json
from datetime import datetime, timezone

API_URL = "https://votre-instance.quantumlogs.cloud/logs"
API_KEY = "votre-cle-api"

logs = [{
    "measurement": "player_connection",
    "timestamp": datetime.now(timezone.utc).isoformat(),
    "tags": {
        "player_name": "John",
        "player_global_id": "76561198000000000",
        "server": "serveur-1"
    },
    "fields": {
        "value": "John s'est connecté au serveur"
    }
}]

response = requests.post(
    API_URL,
    headers={
        "Content-Type": "application/json",
        "Authorization": API_KEY
    },
    json=logs
)

print(f"Status: {response.status_code}")  # 201 = succès
print(f"Body: {response.text}")            # "OK"
```

### JavaScript (Node.js)

```javascript
const API_URL = "https://votre-instance.quantumlogs.cloud/logs";
const API_KEY = "votre-cle-api";

const logs = [{
  measurement: "player_connection",
  timestamp: new Date().toISOString(),
  tags: {
    player_name: "John",
    player_global_id: "76561198000000000",
    server: "serveur-1"
  },
  fields: {
    value: "John s'est connecté au serveur"
  }
}];

const response = await fetch(API_URL, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": API_KEY
  },
  body: JSON.stringify(logs)
});

console.log(`Status: ${response.status}`);  // 201 = succès
console.log(`Body: ${await response.text()}`); // "OK"
```

### C# (Unity / .NET)

```csharp
using System.Net.Http;
using System.Text;
using System.Text.Json;

var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "votre-cle-api");

var logs = new[] {
    new {
        measurement = "player_connection",
        timestamp = DateTime.UtcNow.ToString("o"),
        tags = new { player_name = "John", server = "serveur-1" },
        fields = new { value = "John s'est connecté" }
    }
};

var content = new StringContent(
    JsonSerializer.Serialize(logs),
    Encoding.UTF8,
    "application/json"
);

var response = await client.PostAsync(
    "https://votre-instance.quantumlogs.cloud/logs",
    content
);

Console.WriteLine($"Status: {(int)response.StatusCode}"); // 201 = succès
```

### Lua (Garry's Mod - exemple custom)

```lua
local API_URL = "https://votre-instance.quantumlogs.cloud/logs"
local API_KEY = "votre-cle-api"

local logs = {
    {
        measurement = "player_chat",
        timestamp = os.date("!%Y-%m-%dT%H:%M:%S.000Z"),
        tags = {
            player_name = "John",
            player_global_id = "76561198000000000",
            server = "darkrp-1"
        },
        fields = {
            value = "John: Bonjour tout le monde !"
        }
    }
}

HTTP({
    url = API_URL,
    method = "POST",
    headers = {
        ["Content-Type"] = "application/json",
        ["Authorization"] = API_KEY
    },
    body = util.TableToJSON(logs),
    success = function(code, body)
        print("QuantumLogs: " .. code) -- 201 = succès
    end,
    failed = function(reason)
        print("QuantumLogs Error: " .. reason)
    end
})
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docsnew.quantumlogs.cloud/integration-jeux/api-rest.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
