> ## Documentation Index
> Fetch the complete documentation index at: https://www.octoparse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Usage éditeur

> Comment vos apps publiées ont été appelées sur une période : totaux plus ventilations par jour, heure, app, canal, état, version, code d’erreur ou appelant.

**`GET`** `https://api-datahub.octoparse.com/v1/publisher/usage`

Authentification : clé API requise (`Authorization: Bearer <API Key>`).

Comment vos apps ont été appelées sur une période : totaux de plage, plus ventilations par jour (ou heure pour les plages courtes), app et canal d’appel (deux dimensions croisées possibles), ou ventilations de diagnostic par état terminal, version ou code d’erreur. C’est le pendant éditeur de l’agrégation de facturation : même vocabulaire (`created_from` / `created_to` indexés sur l’heure de début, début inclusif et fin exclusive ; `tz_offset` ne déplace que les bornes de jour ; `data_app` / `triggered_by` restreignent la portée), avec la propriété inversée de « exécutions que j’ai démarrées » vers « apps que je possède » (y compris apps sans release).

Les ventilations jour/heure/app/canal viennent de buckets horaires accumulés à l’état terminal, donc toute plage et tout offset d’heure pleine restent exacts et peu coûteux. Les ventilations état/version/erreur se calculent à la demande depuis les détails d’exécution, donc les deux bornes sont requises et l’écart doit être d’au plus 92 jours (`400 range-too-wide`). Les groupes d’erreur ne couvrent que les exécutions avec erreur ; chaque groupe inclut le message d’erreur le plus récent comme `sample_message`. Les débogages auteur sont exclus par défaut ; les probes de santé plateforme ne comptent jamais. Le succès inclut le succès partiel ; les annulées restent hors dénominateur du taux de succès ; les métriques sans exécutions terminales sont `null`. `amount` est le frais de données payé par les appelants pour ces exécutions, pas le revenu liquidé de l’éditeur.

Les groupes jour/heure montent (les clés `hour` sont l’horloge locale `YYYY-MM-DDTHH:00` sous `tz_offset`, sans suffixe de fuseau). Les autres groupes descendent par nombre d’exécutions.

`totals.callers` est le nombre d’utilisateurs appelants distincts dans la plage, depuis les détails d’exécution, et n’est renseigné que si la plage est bornée et d’au plus 92 jours. `group_by=caller` ventile une **seule app privée ou partagée** par appelant : l’auteur (`caller_kind=owner`) et les utilisateurs actuellement sur la liste de grants (`grantee`) apparaissent sous leur username actuel ; les autres (ex-grantees, appelants d’une période publique) fusionnent dans un groupe `other`. Apps publiques ou plusieurs apps → `400 caller-group-unavailable` : les appelants d’apps publiques restent anonymes et ne sont que comptés.

## Requête

### Paramètres de requête

<ParamField query="group_by" type="string" default="day">
  Une ou deux dimensions, séparées par des virgules : `day` / `hour` / `data_app` / `triggered_by` / `state` / `version` / `error` / `caller` (par ex. `day,data_app`). `day` et `hour` ne se combinent pas ; `state` / `version` / `error` / `caller` exigent une plage bornée d’au plus 92 jours ; `caller` exige aussi exactement une app privée ou partagée. Défaut `day`.
</ParamField>

<ParamField query="data_app" type="string[]">
  Limiter à ces apps (`<username>/<app_name>`, répétable). Défaut : toutes vos apps.
</ParamField>

<ParamField query="created_from" type="string">
  Début inclusif.
</ParamField>

<ParamField query="created_to" type="string">
  Fin exclusive.
</ParamField>

<ParamField query="tz_offset" type="integer" default="0">
  Offset de fuseau en minutes pour buckets jour/heure. Utilisez `480` pour l’heure standard de Chine. Buckets à grain horaire ; offsets de demi-heure arrondis à l’heure.

  Plage de -720 à 840.
</ParamField>

<ParamField query="triggered_by" type="string">
  Limiter à un canal d’appel (`api` / `sdk` / `mcp` / `web`, etc.).
</ParamField>

<ParamField query="include_test" type="boolean" default="False">
  S’il faut inclure les exécutions de débogage auteur.
</ParamField>

<ParamField query="compare" type="boolean" default="False">
  Renvoie aussi `previous_totals` pour la fenêtre de même longueur juste avant `created_from`. Les deux bornes sont requises.
</ParamField>

### Exemple de requête

```bash theme={null}
curl \
  -H "Authorization: Bearer $OCTOPARSE_API_KEY" \
  "https://api-datahub.octoparse.com/v1/publisher/usage?group_by=day,data_app&created_from=2026-09-01T00:00:00%2B08:00&created_to=2026-10-01T00:00:00%2B08:00&tz_offset=480"
```

## Réponse

### 200 succès

```json theme={null}
{
  "data": {
    "range": {
      "created_from": null,
      "created_to": null,
      "tz_offset": 480
    },
    "currency": "CNY",
    "totals": {
      "runs": 2,
      "succeeded": 2,
      "partial": 0,
      "failed": 0,
      "cancelled": 0,
      "success_rate": 1.0,
      "records": 40,
      "avg_duration_ms": 422,
      "amount": 0.04,
      "apps_active": 1,
      "callers": null
    },
    "previous_totals": null,
    "group_by": "day",
    "groups": [
      {
        "runs": 2,
        "succeeded": 2,
        "partial": 0,
        "failed": 0,
        "cancelled": 0,
        "success_rate": 1.0,
        "records": 40,
        "avg_duration_ms": 422,
        "amount": 0.04,
        "day": "2026-09-15",
        "hour": null,
        "namespace": null,
        "app_name": null,
        "channel": null,
        "state": null,
        "version": null,
        "error_code": null,
        "error_category": null,
        "sample_message": null,
        "last_seen_at": null,
        "username": null,
        "caller_kind": null
      }
    ]
  }
}
```

La charge utile est encapsulée dans `data`. Champs :

<ResponseField name="range" type="object" required>
  La plage et l’offset réellement utilisés.

  <Expandable title="champs">
    <ResponseField name="created_from" type="string">
      Début inclusif réellement appliqué.
    </ResponseField>

    <ResponseField name="created_to" type="string">
      Fin exclusive réellement appliquée.
    </ResponseField>

    <ResponseField name="tz_offset" type="integer">
      Offset du bucket jour/heure en minutes.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="currency" type="string">
  Devise.
</ResponseField>

<ResponseField name="totals" type="object" required>
  Totaux de la plage.

  <Expandable title="champs">
    <ResponseField name="runs" type="integer">
      Nombre d’exécutions.
    </ResponseField>

    <ResponseField name="succeeded" type="integer">
      Nombre de succès (inclut le succès partiel).
    </ResponseField>

    <ResponseField name="partial" type="integer">
      Nombre de succès partiels.
    </ResponseField>

    <ResponseField name="failed" type="integer">
      Nombre d’échecs.
    </ResponseField>

    <ResponseField name="cancelled" type="integer">
      Nombre d’annulations.
    </ResponseField>

    <ResponseField name="success_rate" type="number">
      Taux de succès ; les annulées restent hors dénominateur. `null` s’il n’y a pas d’exécutions terminales.
    </ResponseField>

    <ResponseField name="records" type="integer">
      Total d’enregistrements réécrits.
    </ResponseField>

    <ResponseField name="avg_duration_ms" type="integer">
      Durée moyenne d’exécution en millisecondes.
    </ResponseField>

    <ResponseField name="amount" type="number">
      Total des frais de données payés par les appelants.
    </ResponseField>

    <ResponseField name="apps_active" type="integer">
      Nombre d’apps avec au moins une exécution.
    </ResponseField>

    <ResponseField name="callers" type="integer">
      Utilisateurs appelants distincts. `null` si la plage est non bornée ou > 92 jours.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="previous_totals" type="object">
  Totaux de la fenêtre précédente de même longueur quand `compare=true`.

  <Expandable title="champs">
    <ResponseField name="runs" type="integer">
      Nombre d’exécutions.
    </ResponseField>

    <ResponseField name="succeeded" type="integer">
      Nombre de succès (inclut le succès partiel).
    </ResponseField>

    <ResponseField name="partial" type="integer">
      Nombre de succès partiels.
    </ResponseField>

    <ResponseField name="failed" type="integer">
      Nombre d’échecs.
    </ResponseField>

    <ResponseField name="cancelled" type="integer">
      Nombre d’annulations.
    </ResponseField>

    <ResponseField name="success_rate" type="number">
      Taux de succès ; les exécutions annulées restent hors dénominateur.
    </ResponseField>

    <ResponseField name="records" type="integer">
      Total d’enregistrements réécrits.
    </ResponseField>

    <ResponseField name="avg_duration_ms" type="integer">
      Durée moyenne d’exécution en millisecondes.
    </ResponseField>

    <ResponseField name="amount" type="number">
      Total des frais de données payés par les appelants.
    </ResponseField>

    <ResponseField name="apps_active" type="integer">
      Nombre d’apps avec au moins une exécution.
    </ResponseField>

    <ResponseField name="callers" type="integer">
      Appelants (utilisateurs) distincts dans la plage ; calculé depuis les détails d’exécution, donc `null` sauf si les deux bornes sont données et au plus 92 jours d’écart.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="group_by" type="string">
  Dimension(s) réellement utilisée(s).
</ResponseField>

<ResponseField name="groups" type="object[]">
  Lignes de groupe. Chaque ligne porte les mêmes métriques que `totals`, plus les clés de dimension (`day` / `hour` / `data_app` / `triggered_by` / `state` / `version` / `error` / `caller` selon `group_by`).

  <Expandable title="champs">
    <ResponseField name="runs" type="integer">
      Nombre d’exécutions dans le groupe.
    </ResponseField>

    <ResponseField name="succeeded" type="integer">
      Nombre de succès (inclut le succès partiel).
    </ResponseField>

    <ResponseField name="partial" type="integer">
      Nombre de succès partiels.
    </ResponseField>

    <ResponseField name="failed" type="integer">
      Nombre d’échecs.
    </ResponseField>

    <ResponseField name="cancelled" type="integer">
      Nombre d’annulations.
    </ResponseField>

    <ResponseField name="success_rate" type="number">
      Taux de succès du groupe.
    </ResponseField>

    <ResponseField name="records" type="integer">
      Enregistrements réécrits dans le groupe.
    </ResponseField>

    <ResponseField name="avg_duration_ms" type="integer">
      Durée moyenne d’exécution en millisecondes.
    </ResponseField>

    <ResponseField name="amount" type="number">
      Frais de données payés par les appelants du groupe.
    </ResponseField>

    <ResponseField name="day" type="string">
      Clé de jour en regroupement par jour, `YYYY-MM-DD`.
    </ResponseField>

    <ResponseField name="hour" type="string">
      Clé d’heure en regroupement par heure : `YYYY-MM-DDTHH:00` local sous `tz_offset`.
    </ResponseField>

    <ResponseField name="namespace" type="string">
      Nom d’utilisateur éditeur en regroupement par app.
    </ResponseField>

    <ResponseField name="app_name" type="string">
      Nom de l’app en regroupement par app.
    </ResponseField>

    <ResponseField name="channel" type="string">
      Canal d’appel en regroupement par `triggered_by`.
    </ResponseField>

    <ResponseField name="state" type="string">
      État terminal en regroupement par état.
    </ResponseField>

    <ResponseField name="version" type="string">
      Dimension version : version de release épinglée ; `null` en débogage (épinglent un snapshot de build).
    </ResponseField>

    <ResponseField name="error_code" type="string">
      Code d’erreur en regroupement par erreur.
    </ResponseField>

    <ResponseField name="error_category" type="string">
      Catégorie d’erreur en regroupement par erreur.
    </ResponseField>

    <ResponseField name="sample_message" type="string">
      Dimension d’erreur : message de l’exécution la plus récente de ce groupe.
    </ResponseField>

    <ResponseField name="last_seen_at" type="string">
      Horodatage de l’exécution la plus récente du groupe.
    </ResponseField>

    <ResponseField name="username" type="string">
      Dimension appelant : nom d’utilisateur actuel de l’appelant ; `null` pour le groupe `other` ou sans username.
    </ResponseField>

    <ResponseField name="caller_kind" type="string">
      Dimension appelant : `owner` (exécutions de l’éditeur), `grantee` (utilisateur actuellement sur la liste de grants) ou `other` (autres appelants fusionnés).
    </ResponseField>
  </Expandable>
</ResponseField>

### Erreurs

| HTTP | `code`                     | `category`      | Description                                                                                                     |
| ---- | -------------------------- | --------------- | --------------------------------------------------------------------------------------------------------------- |
| 401  | `unauthorized`             | `forbidden`     | Clé API manquante ou invalide.                                                                                  |
| 400  | `invalid-group-by`         | `invalid_input` | `group_by` n’est pas autorisé, ou la combinaison est illégale.                                                  |
| 400  | `range-too-wide`           | `invalid_input` | Cette dimension exige `created_from` et `created_to`, au plus 92 jours d’écart.                                 |
| 400  | `caller-group-unavailable` | `invalid_input` | `group_by=caller` n’accepte exactement qu’une app privée ou partagée.                                           |
| 404  | `app-not-found`            | `not_found`     | L’app n’existe pas, a été renommée, ou est invisible pour la credential actuelle (hors portée privée/partagée). |

Les réponses d’erreur utilisent `{"error": {code, category, message, retryable}}`. Voir <a href="/docs/fr/datahub/api/reference/introduction#errors">Erreurs</a>.

## Bibliothèques clientes

Les SDK Python et JavaScript n’encapsulent pas encore cet endpoint. Appelez REST directement.
