# My Usage

Monitor your API consumption against your plan limits. Track requests by HTTP method and period to understand usage patterns and plan capacity needs.

Source: https://docs.gunspec.io/en/api/me-usage

## Get Usage Stats

`GET /v1/me/usage`

Auth: API key required  
Tier: Explorer+

Returns request counts for your key against your plan allowance, what is left of today's daily limit and when it resets, and how many requests came through the hosted MCP server against its lower daily limit. Defaults to the current billing month; pass `days` for a trailing window instead.

### Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `month` | string | no | Billing month to report on, formatted YYYY-MM |
| `days` | integer | no | Trailing window in days, as an alternative to month |

### Response 200 (application/json)

| Field | Type | Description |
| --- | --- | --- |
| `data` | object | The response payload. |
| `data.currentMonth` | object | Totals for the reported period, meaning the current billing month, or the trailing window when `days` is given. |
| `data.currentMonth.used` | integer | Requests served in the reported period across every key on the account. Calls a limit refused with a 429 are not counted: they spent nothing, and this is the figure the monthly allowance is enforced against. |
| `data.currentMonth.limit` | integer | Requests your plan allows in the period. Enforced: once `used` reaches it every call is refused with `MONTHLY_CAP_EXCEEDED` until `resetsAt`. |
| `data.currentMonth.remaining` | integer | Requests left in the period, never below zero. |
| `data.currentMonth.percentage` | number | Share of records, 0 to 100. |
| `data.currentMonth.resetsAt` | string | When the monthly counter returns to zero: midnight UTC on the first of the next month, for every plan. The same instant as `X-Monthly-Reset`. |
| `data.daily` | object | What is left of today, against the limit that is enforced. Each key is counted and limited on its own. |
| `data.daily.limitPerKey` | integer \| null | Requests one key may make per UTC day on this plan. The limit applies to each key separately, which is why there is no account total to compare it with. Null when the plan has no daily ceiling. |
| `data.daily.usedToday` | integer | Requests made today (UTC) across every key on the account. Not comparable with `limitPerKey` unless the account has one key: each key is held to the limit on its own. |
| `data.daily.busiestKeyToday` | object \| null | The key nearest its daily limit, or null when no key has made a request today. |
| `data.daily.resetsAt` | string | When every daily counter returns to zero: the next midnight UTC. The same instant as `X-Daily-Reset`. |
| `data.mcp` | object | Usage through the hosted MCP server, a subset of the requests above. |
| `data.mcp.usedThisMonth` | integer | Calls made through the MCP server in the reported month. Already counted in `currentMonth.used`, never on top of it. |
| `data.mcp.usedToday` | integer | MCP calls today (UTC) across every key on the account. |
| `data.mcp.dailyLimitPerKey` | integer | MCP calls one key may make per UTC day on this plan. The limit applies to each key separately. |
| `data.mcp.busiestKeyToday` | object \| null | The key nearest its daily MCP limit, or null when no key has made an MCP call today. |
| `data.mcp.resetsAt` | string | When the daily MCP counters return to zero: the next midnight UTC. |
| `data.progress` | object | Your standing. Experience is earned per call and weighted by what the call is: resolving a name, asking what fits a firearm or comparing two records is worth several times a page of a list, because the point is integration depth rather than traffic. Earned by an SDK, the MCP server, a script or a request tool; a browser earns nothing, since the reference has a Try It button and a page left open should not outrank a production service. A `304` earns nothing, on the same reasoning that it spends no quota, and a call that failed earns nothing either. |
| `data.progress.xp` | integer | Experience earned across every key on the account, for its whole life. |
| `data.progress.xpToday` | integer | Experience earned today (UTC). |
| `data.progress.dailyXpCap` | integer | The most one key can earn in a UTC day. A ceiling rather than a target: reaching it every day is not how the levels are meant to be climbed. |
| `data.progress.level` | integer | Your level, derived from `xp` alone. Nothing else moves it. |
| `data.progress.levelStartsAt` | integer | The experience this level began at. |
| `data.progress.nextLevelAt` | integer | The experience the next level begins at. |
| `data.progress.streakDays` | integer | Consecutive days you have called the API, counting today. A day you did not call breaks it, though yesterday still counts as unbroken so a timezone does not cost you a streak. Reported, never rewarded: no experience is paid for showing up. |
| `data.progress.daysActive` | integer | Days you have called the API at all, over the last two years. |
| `data.progress.operationsUsed` | integer | Documented operations you have called at least once. Counted from the request log by the nightly job, so an operation you called for the first time today appears tomorrow. |
| `data.progress.operationsAvailable` | integer | Documented operations there are to call, counted from this document rather than written down, so it cannot fall behind a route added today. |
| `data.endpointCredits` | object | Calls to endpoints above your plan, attached to the account so every key draws on the same balance. Every new account starts with a one-time grant covering any endpoint up to Studio, and the team can give more. A call spent this way is served exactly as the endpoint's own plan would be (full fields, that plan's paging depth), is marked with an `X-Endpoint-Credit: spent` header, and still counts against your plan's per-minute and daily limits. A call that fails, or answers `304`, is given back. |
| `data.endpointCredits.remaining` | integer | Calls left across every credit that can still be spent. |
| `data.endpointCredits.credits` | object[] | Every credit the account has had, newest first, spent ones included. |
| `data.dailyBreakdown` | object[] | Requests per day over the reported period, oldest first. Days with no traffic are omitted. |
| `data.dailyBreakdown[].date` | string | The day, `YYYY-MM-DD` in UTC. |
| `data.dailyBreakdown[].count` | integer | How many records fall in this bucket. |
| `data.dailyBreakdown[].mcpCount` | integer | Of `count`, the requests made through the MCP server. |
| `data.perKey` | object[] | Requests per API key over the reported period. |
| `data.perKey[].keyId` | string | Id of the API key. The key itself is never returned. |
| `data.perKey[].keyName` | string | The label you gave the key. |
| `data.perKey[].count` | integer | How many records fall in this bucket. |
| `data.perKey[].mcpCount` | integer | Of `count`, the requests made through the MCP server. |
| `data.perKey[].mcpToday` | integer | MCP calls this key made today (UTC), the figure its daily MCP limit is held against. |
| `data.perKey[].today` | integer | Requests this key made today (UTC), the figure its daily limit is held against. Counts calls the limit refused. |
| `data.perKey[].remainingToday` | integer \| null | Requests this key has left today, never below zero. Null when the plan has no daily ceiling. |
| `data.keyCount` | integer | How many API keys the account holds. |
| `data.tier` | object | The allowances of the plan the account is on. |
| `data.tier.name` | string | Display name, as the maker writes it. |
| `data.tier.requestsPerMonth` | integer | Monthly request allowance on this plan, enforced for the whole account. |
| `data.tier.requestsPerDay` | integer \| null | Requests each key may make per UTC day on this plan: the limit that is enforced. Null when the plan has no daily ceiling. |
| `data.tier.rateLimit` | integer | Requests per minute this plan allows. |
| `data.tier.mcpCallsPerDay` | integer | MCP calls each key may make per UTC day on this plan. |

```json
{
  "success": true,
  "data": {
    "currentMonth": {
      "used": 1284,
      "limit": 25000,
      "remaining": 23716,
      "percentage": 5.1,
      "resetsAt": "2026-10-01T00:00:00.000Z"
    },
    "daily": {
      "limitPerKey": 5000,
      "usedToday": 1840,
      "busiestKeyToday": {
        "keyId": "key_01H8...",
        "keyName": "Production",
        "used": 1670,
        "remaining": 3330,
        "percentage": 33
      },
      "resetsAt": "2026-09-18T00:00:00.000Z"
    },
    "mcp": {
      "usedThisMonth": 312,
      "usedToday": 41,
      "dailyLimitPerKey": 2500,
      "busiestKeyToday": {
        "keyId": "key_01H8...",
        "keyName": "Claude Desktop",
        "used": 38,
        "percentage": 2
      },
      "resetsAt": "2026-09-18T00:00:00.000Z"
    },
    "progress": {
      "xp": 4210,
      "xpToday": 180,
      "dailyXpCap": 500,
      "level": 10,
      "levelStartsAt": 4050,
      "nextLevelAt": 5000,
      "streakDays": 12,
      "daysActive": 96,
      "operationsUsed": 31,
      "operationsAvailable": 145
    },
    "endpointCredits": {
      "remaining": 50,
      "credits": [
        {
          "id": "9f2c1e0a-5b7d-4c1e-8a3f-2d6b9e4c7a10",
          "source": "welcome",
          "operations": [
            "get /v1/firearms/{id}"
          ],
          "maxTier": "studio",
          "callsGranted": 50,
          "callsUsed": 12,
          "callsRemaining": 38,
          "expiresAt": "2026-12-31T00:00:00.000Z",
          "status": "active",
          "createdAt": "2026-09-10 08:30:00"
        }
      ]
    },
    "dailyBreakdown": [
      {
        "date": "2026-09-10",
        "count": 2187,
        "mcpCount": 64
      }
    ],
    "perKey": [
      {
        "keyId": "key_01H8...",
        "keyName": "Production",
        "count": 1603,
        "mcpCount": 210,
        "mcpToday": 38,
        "today": 1670,
        "remainingToday": 3330
      }
    ],
    "keyCount": 2,
    "tier": {
      "name": "Studio",
      "requestsPerMonth": 150000,
      "requestsPerDay": 10000,
      "rateLimit": 300,
      "mcpCallsPerDay": 2500
    }
  }
}
```

### Errors

| Status | Code | Message |
| --- | --- | --- |
| 400 | `VALIDATION_ERROR` | Validation error |
| 401 | `UNAUTHORIZED` | API key required |
| 403 | `FORBIDDEN` | Valid key, not permitted |
| 429 | `RATE_LIMITED` | Rate limit exceeded |
| 500 | `INTERNAL_ERROR` | Unexpected server error |

### Notes

- `currentMonth` is the plan's monthly allowance, enforced for the whole account. `used` counts only requests that were served: a call a limit refused, and a `304`, do not spend it. `remaining` is what is left and `resetsAt` is midnight UTC on the 1st for every plan, not the billing date. `daily` and `mcp` reset at midnight UTC (`daily.resetsAt`).
- `daily` is the limit that is enforced: requests per key per UTC day, held against each key on its own. `used` counts the calls the limit refused too, so a key that kept calling after being told to stop shows a figure past the limit.
- This call is itself a request that counts. Pace from the `X-Daily-*` and `X-Monthly-*` response headers and use this endpoint to reconcile and to see every key at once.
- Every response from a plan with a daily limit carries `X-Daily-Limit`, `X-Daily-Remaining` and `X-Daily-Reset`, and every response to a call made with a key carries `X-Monthly-Limit`, `X-Monthly-Remaining` and `X-Monthly-Reset`, so a client can pace itself without calling this endpoint. Each remaining figure is what is left after the call that returned it. There is no per-minute equivalent: the edge limiter reports whether a request was allowed, not how much of the minute is left.

### Example

```bash
curl --request GET \
  --url 'https://api.gunspec.io/v1/me/usage?month=2026-08' \
  --header 'X-API-Key: your_key'
```
