RequestRocketRequestRocketDocs
API ReferenceCore API

Meters API

Configure usage meters on proxies to track consumption, enforce rate limits, or aggregate telemetry without restricting access

Meters API

Configure usage meters on proxies to track and enforce consumption limits across time windows. Meters can count requests or extract numeric values from responses (such as AI token usage), and can optionally apply only to requests matching specific predicates.

Meters can be configured with or without limits. When limits are set, requests that exceed a window threshold are rejected with a 429 response. When no limits are configured, the meter still participates in telemetry aggregation — useful for observability and reporting without restricting API access.

Endpoints

Meters are scoped to a proxy:

MethodEndpointDescription
GET/api/clients/{clientId}/proxies/{proxyId}/metersList all meters for a proxy
GET/api/clients/{clientId}/proxies/{proxyId}/meters/{meterId}Get a single meter
POST/api/clients/{clientId}/proxies/{proxyId}/metersCreate a meter
PUT/api/clients/{clientId}/proxies/{proxyId}/meters/{meterId}Update a meter
DELETE/api/clients/{clientId}/proxies/{proxyId}/meters/{meterId}Delete a meter

Meters are proxy-scoped and inherit their region from the parent proxy. The meterRegion field is set automatically at creation time.

Meter Types

TypeDescription
request_countIncrements a counter by 1 for each matching request
response_valueExtracts a numeric value from the response (body or header) and accumulates it

When meterType is response_value, an extraction configuration is required specifying where and how to extract the numeric value from each response.

Create Meter

Create a new usage meter on a proxy.

Request

POST /api/clients/{clientId}/proxies/{proxyId}/meters HTTP/1.1
Host: api.requestrocket.com
Authorization: {user_token}
Content-Type: application/json

{
  "meterType": "response_value",
  "meterActive": true,
  "extraction": {
    "location": "body",
    "path": "usage.total_tokens",
    "defaultValue": 0
  },
  "limits": {
    "day": 100000,
    "month": 2000000
  },
  "notes": "Track AI token usage per day and month"
}

Request Body

FieldTypeRequiredDescription
meterTypestringYesrequest_count or response_value
meterActivebooleanYesWhether the meter is actively enforced
limitsobjectNoLimit thresholds per time window (see Limits). Omit entirely for aggregate-only meters
notesstringNoDescription of the meter
extractionobjectConditionalRequired when meterType is response_value (see Extraction)
meterModestringNoall (default) or conditional
effectstringNoFor conditional meters: include or exclude
methodsarrayNoHTTP methods this meter applies to
pathobjectNoPath predicate
queryarrayNoQuery parameter predicates
headersarrayNoHeader predicates
bodyarrayNoRequest body predicates
tokenarrayNoJWT claim predicates
variablesarrayNoVariable bindings for pattern interpolation

Limits

The limits object defines the maximum accumulated value allowed per time window. All fields are optional — include only the windows you want to enforce. If limits is omitted entirely, the meter tracks usage in telemetry without ever blocking a request.

FieldTypeDescription
minutenumberMaximum value per minute
hournumberMaximum value per hour
daynumberMaximum value per day
monthnumberMaximum value per month

Extraction

Required when meterType is response_value. Defines how to extract the numeric value from each response.

FieldTypeRequiredDescription
locationstringYesbody or header
pathstringConditionalDot-notation path into the response body (e.g. usage.total_tokens). Required when location is body
headerNamestringConditionalResponse header name to read. Required when location is header
defaultValuenumberNoFallback value used when the extracted value is absent or non-numeric

Response

{
  "meters": [
    {
      "pKey": "proxy_abc123",
      "sKey": "meter_def456",
      "userId": "user_789",
      "clientId": "client_123",
      "parentId": "proxy_abc123",
      "meterRegion": "us-east-1",
      "meterType": "response_value",
      "meterActive": true,
      "extraction": {
        "location": "body",
        "path": "usage.total_tokens",
        "defaultValue": 0
      },
      "limits": {
        "day": 100000,
        "month": 2000000
      },
      "notes": "Track AI token usage per day and month",
      "meterMode": "all",
      "createdAt": "2024-06-01T10:00:00.000Z",
      "updatedAt": "2024-06-01T10:00:00.000Z"
    }
  ],
  "message": "Success"
}

Example

curl -X POST "https://api.requestrocket.com/api/clients/${CLIENT_ID}/proxies/${PROXY_ID}/meters" \
  -H "Authorization: ${USER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "meterType": "response_value",
    "meterActive": true,
    "extraction": {
      "location": "body",
      "path": "usage.total_tokens",
      "defaultValue": 0
    },
    "limits": {
      "day": 100000,
      "month": 2000000
    },
    "notes": "Track AI token usage per day and month"
  }'
const response = await fetch(
  `https://api.requestrocket.com/api/clients/${clientId}/proxies/${proxyId}/meters`,
  {
    method: 'POST',
    headers: {
      'Authorization': process.env.USER_TOKEN,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      meterType: 'response_value',
      meterActive: true,
      extraction: {
        location: 'body',
        path: 'usage.total_tokens',
        defaultValue: 0
      },
      limits: {
        day: 100000,
        month: 2000000
      },
      notes: 'Track AI token usage per day and month'
    })
  }
);

const data = await response.json();
console.log('Meter created:', data.meters[0]);
import requests
import os

client_id = "your-client-id"
proxy_id = "your-proxy-id"

response = requests.post(
    f'https://api.requestrocket.com/api/clients/{client_id}/proxies/{proxy_id}/meters',
    headers={'Authorization': os.getenv('USER_TOKEN')},
    json={
        'meterType': 'response_value',
        'meterActive': True,
        'extraction': {
            'location': 'body',
            'path': 'usage.total_tokens',
            'defaultValue': 0
        },
        'limits': {
            'day': 100000,
            'month': 2000000
        },
        'notes': 'Track AI token usage per day and month'
    }
)

data = response.json()
print(f"Meter created: {data['meters'][0]['sKey']}")
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
)

type MeterExtraction struct {
    Location     string  `json:"location"`
    Path         string  `json:"path"`
    DefaultValue float64 `json:"defaultValue"`
}

type MeterLimits struct {
    Day   int `json:"day"`
    Month int `json:"month"`
}

type MeterRequest struct {
    MeterType  string          `json:"meterType"`
    MeterActive bool           `json:"meterActive"`
    Extraction MeterExtraction `json:"extraction"`
    Limits     MeterLimits     `json:"limits"`
    Notes      string          `json:"notes"`
}

func main() {
    clientId := "your-client-id"
    proxyId := "your-proxy-id"

    requestBody, _ := json.Marshal(MeterRequest{
        MeterType:  "response_value",
        MeterActive: true,
        Extraction: MeterExtraction{
            Location:     "body",
            Path:         "usage.total_tokens",
            DefaultValue: 0,
        },
        Limits: MeterLimits{Day: 100000, Month: 2000000},
        Notes:  "Track AI token usage per day and month",
    })

    url := fmt.Sprintf("https://api.requestrocket.com/api/clients/%s/proxies/%s/meters", clientId, proxyId)
    req, _ := http.NewRequest("POST", url, bytes.NewBuffer(requestBody))
    req.Header.Set("Authorization", os.Getenv("USER_TOKEN"))
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, _ := client.Do(req)
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}
import java.net.http.*;
import java.net.URI;

public class CreateMeter {
    public static void main(String[] args) throws Exception {
        String clientId = "your-client-id";
        String proxyId = "your-proxy-id";
        String json = "{"
            + "\"meterType\": \"response_value\","
            + "\"meterActive\": true,"
            + "\"extraction\": {"
            + "  \"location\": \"body\","
            + "  \"path\": \"usage.total_tokens\","
            + "  \"defaultValue\": 0"
            + "},"
            + "\"limits\": {\"day\": 100000, \"month\": 2000000},"
            + "\"notes\": \"Track AI token usage per day and month\""
            + "}";

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.requestrocket.com/api/clients/" + clientId + "/proxies/" + proxyId + "/meters"))
            .header("Authorization", System.getenv("USER_TOKEN"))
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(json))
            .build();

        HttpResponse<String> response = client.send(request,
            HttpResponse.BodyHandlers.ofString());

        System.out.println(response.body());
    }
}

List Meters

Get all meters configured for a proxy.

Request

GET /api/clients/{clientId}/proxies/{proxyId}/meters HTTP/1.1
Host: api.requestrocket.com
Authorization: {user_token}

Response

{
  "meters": [
    {
      "pKey": "proxy_abc123",
      "sKey": "meter_def456",
      "userId": "user_789",
      "clientId": "client_123",
      "parentId": "proxy_abc123",
      "meterRegion": "us-east-1",
      "meterType": "response_value",
      "meterActive": true,
      "extraction": {
        "location": "body",
        "path": "usage.total_tokens",
        "defaultValue": 0
      },
      "limits": {
        "day": 100000,
        "month": 2000000
      },
      "notes": "Track AI token usage per day and month",
      "meterMode": "all",
      "createdAt": "2024-06-01T10:00:00.000Z",
      "updatedAt": "2024-06-01T10:00:00.000Z"
    }
  ],
  "message": "Success"
}

Example

curl -X GET "https://api.requestrocket.com/api/clients/${CLIENT_ID}/proxies/${PROXY_ID}/meters" \
  -H "Authorization: ${USER_TOKEN}"
const response = await fetch(
  `https://api.requestrocket.com/api/clients/${clientId}/proxies/${proxyId}/meters`,
  {
    headers: {
      'Authorization': process.env.USER_TOKEN
    }
  }
);

const data = await response.json();
console.log('Meters:', data.meters);
import requests
import os

client_id = "your-client-id"
proxy_id = "your-proxy-id"

response = requests.get(
    f'https://api.requestrocket.com/api/clients/{client_id}/proxies/{proxy_id}/meters',
    headers={'Authorization': os.getenv('USER_TOKEN')}
)

data = response.json()
print(f"Found {len(data['meters'])} meters")
package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
)

type Response struct {
    Meters  []map[string]interface{} `json:"meters"`
    Message string                   `json:"message"`
}

func main() {
    clientId := "your-client-id"
    proxyId := "your-proxy-id"

    url := fmt.Sprintf("https://api.requestrocket.com/api/clients/%s/proxies/%s/meters", clientId, proxyId)
    req, _ := http.NewRequest("GET", url, nil)
    req.Header.Set("Authorization", os.Getenv("USER_TOKEN"))

    client := &http.Client{}
    resp, _ := client.Do(req)
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    var result Response
    json.Unmarshal(body, &result)

    fmt.Printf("Found %d meters\n", len(result.Meters))
}
import java.net.http.*;
import java.net.URI;
import com.google.gson.*;

public class ListMeters {
    public static void main(String[] args) throws Exception {
        String clientId = "your-client-id";
        String proxyId = "your-proxy-id";

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.requestrocket.com/api/clients/" + clientId + "/proxies/" + proxyId + "/meters"))
            .header("Authorization", System.getenv("USER_TOKEN"))
            .GET()
            .build();

        HttpResponse<String> response = client.send(request,
            HttpResponse.BodyHandlers.ofString());

        JsonObject json = JsonParser.parseString(response.body()).getAsJsonObject();
        JsonArray meters = json.getAsJsonArray("meters");
        System.out.println("Found " + meters.size() + " meters");
    }
}

Get Meter

Retrieve a single meter by ID.

Request

GET /api/clients/{clientId}/proxies/{proxyId}/meters/{meterId} HTTP/1.1
Host: api.requestrocket.com
Authorization: {user_token}

Response

{
  "meters": [
    {
      "pKey": "proxy_abc123",
      "sKey": "meter_def456",
      "userId": "user_789",
      "clientId": "client_123",
      "parentId": "proxy_abc123",
      "meterRegion": "us-east-1",
      "meterType": "request_count",
      "meterActive": true,
      "limits": {
        "minute": 60,
        "hour": 1000
      },
      "notes": "Rate limit per credential",
      "meterMode": "all",
      "createdAt": "2024-06-01T10:00:00.000Z",
      "updatedAt": "2024-06-01T10:00:00.000Z"
    }
  ],
  "message": "Success"
}

Update Meter

Partially update an existing meter. Only the fields you provide are changed.

Request

PUT /api/clients/{clientId}/proxies/{proxyId}/meters/{meterId} HTTP/1.1
Host: api.requestrocket.com
Authorization: {user_token}
Content-Type: application/json

{
  "meterActive": false,
  "limits": {
    "day": 50000,
    "month": 1000000
  }
}

Request Body

All fields are optional. Fields omitted from the request retain their current values.

FieldTypeDescription
meterTypestringrequest_count or response_value
meterActivebooleanWhether the meter is actively enforced
limitsobjectLimit thresholds per time window
notesstringDescription of the meter
extractionobjectExtraction configuration
meterModestringall or conditional
effectstringinclude or exclude
methodsarrayHTTP methods this meter applies to
pathobjectPath predicate
queryarrayQuery parameter predicates
headersarrayHeader predicates
bodyarrayRequest body predicates
tokenarrayJWT claim predicates
variablesarrayVariable bindings for pattern interpolation

Response

{
  "meters": [
    {
      "pKey": "proxy_abc123",
      "sKey": "meter_def456",
      "userId": "user_789",
      "clientId": "client_123",
      "parentId": "proxy_abc123",
      "meterRegion": "us-east-1",
      "meterType": "response_value",
      "meterActive": false,
      "extraction": {
        "location": "body",
        "path": "usage.total_tokens",
        "defaultValue": 0
      },
      "limits": {
        "day": 50000,
        "month": 1000000
      },
      "notes": "Track AI token usage per day and month",
      "meterMode": "all",
      "createdAt": "2024-06-01T10:00:00.000Z",
      "updatedAt": "2024-06-02T08:30:00.000Z"
    }
  ],
  "message": "Success"
}

Example

curl -X PUT "https://api.requestrocket.com/api/clients/${CLIENT_ID}/proxies/${PROXY_ID}/meters/${METER_ID}" \
  -H "Authorization: ${USER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "meterActive": false,
    "limits": {
      "day": 50000,
      "month": 1000000
    }
  }'
const response = await fetch(
  `https://api.requestrocket.com/api/clients/${clientId}/proxies/${proxyId}/meters/${meterId}`,
  {
    method: 'PUT',
    headers: {
      'Authorization': process.env.USER_TOKEN,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      meterActive: false,
      limits: {
        day: 50000,
        month: 1000000
      }
    })
  }
);

const data = await response.json();
console.log('Meter updated:', data.meters[0]);
import requests
import os

client_id = "your-client-id"
proxy_id = "your-proxy-id"
meter_id = "your-meter-id"

response = requests.put(
    f'https://api.requestrocket.com/api/clients/{client_id}/proxies/{proxy_id}/meters/{meter_id}',
    headers={'Authorization': os.getenv('USER_TOKEN')},
    json={
        'meterActive': False,
        'limits': {
            'day': 50000,
            'month': 1000000
        }
    }
)

data = response.json()
print(f"Meter updated: {data['meters'][0]['sKey']}")
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
)

type MeterUpdate struct {
    MeterActive bool        `json:"meterActive"`
    Limits      MeterLimits `json:"limits"`
}

type MeterLimits struct {
    Day   int `json:"day"`
    Month int `json:"month"`
}

func main() {
    clientId := "your-client-id"
    proxyId := "your-proxy-id"
    meterId := "your-meter-id"

    requestBody, _ := json.Marshal(MeterUpdate{
        MeterActive: false,
        Limits:      MeterLimits{Day: 50000, Month: 1000000},
    })

    url := fmt.Sprintf("https://api.requestrocket.com/api/clients/%s/proxies/%s/meters/%s", clientId, proxyId, meterId)
    req, _ := http.NewRequest("PUT", url, bytes.NewBuffer(requestBody))
    req.Header.Set("Authorization", os.Getenv("USER_TOKEN"))
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, _ := client.Do(req)
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}
import java.net.http.*;
import java.net.URI;

public class UpdateMeter {
    public static void main(String[] args) throws Exception {
        String clientId = "your-client-id";
        String proxyId = "your-proxy-id";
        String meterId = "your-meter-id";
        String json = "{"
            + "\"meterActive\": false,"
            + "\"limits\": {\"day\": 50000, \"month\": 1000000}"
            + "}";

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.requestrocket.com/api/clients/" + clientId + "/proxies/" + proxyId + "/meters/" + meterId))
            .header("Authorization", System.getenv("USER_TOKEN"))
            .header("Content-Type", "application/json")
            .PUT(HttpRequest.BodyPublishers.ofString(json))
            .build();

        HttpResponse<String> response = client.send(request,
            HttpResponse.BodyHandlers.ofString());

        System.out.println(response.body());
    }
}

Delete Meter

Remove a meter from a proxy.

Request

DELETE /api/clients/{clientId}/proxies/{proxyId}/meters/{meterId} HTTP/1.1
Host: api.requestrocket.com
Authorization: {user_token}

Response

{
  "message": "Meter deleted successfully from all tables"
}

Example

curl -X DELETE "https://api.requestrocket.com/api/clients/${CLIENT_ID}/proxies/${PROXY_ID}/meters/${METER_ID}" \
  -H "Authorization: ${USER_TOKEN}"
const response = await fetch(
  `https://api.requestrocket.com/api/clients/${clientId}/proxies/${proxyId}/meters/${meterId}`,
  {
    method: 'DELETE',
    headers: {
      'Authorization': process.env.USER_TOKEN
    }
  }
);

const data = await response.json();
console.log(data.message);
import requests
import os

client_id = "your-client-id"
proxy_id = "your-proxy-id"
meter_id = "your-meter-id"

response = requests.delete(
    f'https://api.requestrocket.com/api/clients/{client_id}/proxies/{proxy_id}/meters/{meter_id}',
    headers={'Authorization': os.getenv('USER_TOKEN')}
)

data = response.json()
print(data['message'])
package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
)

type Response struct {
    Message string `json:"message"`
}

func main() {
    clientId := "your-client-id"
    proxyId := "your-proxy-id"
    meterId := "your-meter-id"

    url := fmt.Sprintf("https://api.requestrocket.com/api/clients/%s/proxies/%s/meters/%s", clientId, proxyId, meterId)
    req, _ := http.NewRequest("DELETE", url, nil)
    req.Header.Set("Authorization", os.Getenv("USER_TOKEN"))

    client := &http.Client{}
    resp, _ := client.Do(req)
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    var result Response
    json.Unmarshal(body, &result)

    fmt.Println(result.Message)
}
import java.net.http.*;
import java.net.URI;
import com.google.gson.*;

public class DeleteMeter {
    public static void main(String[] args) throws Exception {
        String clientId = "your-client-id";
        String proxyId = "your-proxy-id";
        String meterId = "your-meter-id";

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.requestrocket.com/api/clients/" + clientId + "/proxies/" + proxyId + "/meters/" + meterId))
            .header("Authorization", System.getenv("USER_TOKEN"))
            .DELETE()
            .build();

        HttpResponse<String> response = client.send(request,
            HttpResponse.BodyHandlers.ofString());

        JsonObject json = JsonParser.parseString(response.body()).getAsJsonObject();
        System.out.println(json.get("message").getAsString());
    }
}

Conditional Metering

By default a meter applies to all requests (meterMode: "all"). Set meterMode to "conditional" to restrict metering to requests that match (or do not match) a set of predicates.

FieldTypeDescription
meterModestringall — meter every request; conditional — filter by predicates
effectstringinclude — only meter matching requests; exclude — meter all requests except matching ones
methodsarrayHTTP methods to match (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS)
pathobjectPath predicate
queryarrayQuery parameter predicates (AND semantics)
headersarrayHeader predicates (AND semantics)
bodyarrayRequest body predicates (AND semantics)
tokenarrayJWT claim predicates (AND semantics)
variablesarrayVariable bindings for pattern interpolation

Example — Track Token Usage Only for POST Requests

{
  "meterType": "response_value",
  "meterActive": true,
  "meterMode": "conditional",
  "effect": "include",
  "methods": ["POST"],
  "extraction": {
    "location": "body",
    "path": "usage.total_tokens",
    "defaultValue": 0
  },
  "limits": {
    "day": 100000
  },
  "notes": "Count tokens only on POST completions"
}

Example — Exclude Health Check Requests from Count

{
  "meterType": "request_count",
  "meterActive": true,
  "meterMode": "conditional",
  "effect": "exclude",
  "path": {
    "pattern": "^/health",
    "presence": "present"
  },
  "limits": {
    "minute": 60,
    "hour": 1000
  },
  "notes": "Rate limit all requests except health checks"
}

Meter Object Reference

The full meter object returned by GET, POST, and PUT responses:

FieldTypeDescription
pKeystringParent key (proxy ID)
sKeystringSort key (meter ID)
userIdstringID of the user who created the meter
clientIdstringID of the client that owns the meter
parentIdstringParent proxy ID
meterRegionstringAWS region inherited from the parent proxy
meterTypestringrequest_count or response_value
meterActivebooleanWhether the meter is actively enforced
limitsobjectLimit thresholds per time window
extractionobjectExtraction config (present when meterType is response_value)
notesstringDescription of the meter
meterModestringall or conditional
effectstringinclude or exclude (for conditional meters)
methodsarrayHTTP methods this meter applies to
pathobjectPath predicate
queryarrayQuery parameter predicates
headersarrayHeader predicates
bodyarrayRequest body predicates
tokenarrayJWT claim predicates
variablesarrayVariable bindings
createdAtstringISO 8601 creation timestamp
updatedAtstringISO 8601 last-updated timestamp

Next Steps

On this page