The Track Endpoint
POST /api/v1/sdk/track
X-API-Key: org_live_<your_key>
Request Body
{
"meter_token": "string (required)",
"customer_external_id": "string (required)",
"quantity": 1,
"timestamp": "2025-01-15T10:30:00Z",
"idempotency_key": "string",
"metadata": {
"key": "value"
}
}
| Field | Required | Description |
|---|---|---|
meter_token | ✅ | Unique token from your meter |
customer_external_id | ✅ | Your customer’s ID |
quantity | ✅ | Usage amount (> 0) |
timestamp | Defaults to now if omitted | |
idempotency_key | Prevents duplicate events on retry | |
metadata | Extra data; required user_id key for UNIQUE_COUNT meters |
Language Examples
- Python
- Node.js
- Go
import requests
import uuid
FLUXRATE_API_KEY = "org_live_your_key"
FLUXRATE_BASE_URL = "https://api.fluxrate.co/api/v1"
def track_usage(
meter_token: str,
customer_external_id: str,
quantity: float,
idempotency_key: str = None,
metadata: dict = None
) -> dict:
"""Track a usage event with Fluxrate."""
payload = {
"meter_token": meter_token,
"customer_external_id": customer_external_id,
"quantity": quantity,
}
if idempotency_key:
payload["idempotency_key"] = idempotency_key
if metadata:
payload["metadata"] = metadata
response = requests.post(
f"{FLUXRATE_BASE_URL}/sdk/track",
headers={
"Content-Type": "application/json",
"X-API-Key": FLUXRATE_API_KEY,
},
json=payload,
timeout=5,
)
response.raise_for_status()
return response.json()
# Example usage
try:
result = track_usage(
meter_token="550e8400-e29b-41d4-a716-446655440000",
customer_external_id="acme-corp-001",
quantity=100,
idempotency_key=f"order_{order_id}_api_calls",
)
print(f"Tracked event: {result['id']}")
except requests.exceptions.RequestException as e:
# Log and handle gracefully — don't fail the main request
logger.error(f"Failed to track usage: {e}")
const FLUXRATE_API_KEY = process.env.FLUXRATE_API_KEY;
const FLUXRATE_BASE_URL = 'https://api.fluxrate.co/api/v1';
async function trackUsage({
meterToken,
customerExternalId,
quantity,
idempotencyKey,
metadata,
}) {
const response = await fetch(`${FLUXRATE_BASE_URL}/sdk/track`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': FLUXRATE_API_KEY,
},
body: JSON.stringify({
meter_token: meterToken,
customer_external_id: customerExternalId,
quantity,
...(idempotencyKey && { idempotency_key: idempotencyKey }),
...(metadata && { metadata }),
}),
signal: AbortSignal.timeout(5000),
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Fluxrate track failed: ${error.detail || response.status}`);
}
return response.json();
}
// Example usage (fire-and-forget)
trackUsage({
meterToken: '550e8400-e29b-41d4-a716-446655440000',
customerExternalId: 'acme-corp-001',
quantity: 1,
idempotencyKey: `req_${requestId}`,
}).catch(err => console.error('Failed to track usage:', err));
package fluxrate
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"time"
)
type TrackRequest struct {
MeterToken string `json:"meter_token"`
CustomerExternalID string `json:"customer_external_id"`
Quantity float64 `json:"quantity"`
IdempotencyKey string `json:"idempotency_key,omitempty"`
Timestamp *time.Time `json:"timestamp,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
}
func TrackUsage(apiKey string, req TrackRequest) error {
body, err := json.Marshal(req)
if err != nil {
return fmt.Errorf("marshal: %w", err)
}
httpReq, err := http.NewRequest(
"POST",
"https://api.fluxrate.co/api/v1/sdk/track",
bytes.NewReader(body),
)
if err != nil {
return err
}
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("X-API-Key", apiKey)
client := &http.Client{Timeout: 5 * time.Second}
resp, err := client.Do(httpReq)
if err != nil {
return fmt.Errorf("request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusCreated {
return fmt.Errorf("unexpected status: %d", resp.StatusCode)
}
return nil
}
Tracking UNIQUE_COUNT Events
ForUNIQUE_COUNT meters, include the value to count in metadata.user_id:
{
"meter_token": "...",
"customer_external_id": "acme-corp-001",
"quantity": 1,
"metadata": {
"user_id": "end_user_456"
}
}
Best Practices
Use idempotency keys
Use idempotency keys
Always pass a unique
idempotency_key so it’s safe to retry failed requests without double-counting.idempotency_key = f"job_{job_id}_step_3"
Track asynchronously
Track asynchronously
Don’t block your main request path waiting for Fluxrate’s response. Track usage in a background task or fire-and-forget.
asyncio.create_task(track_usage(...))
Handle failures gracefully
Handle failures gracefully
Log tracking failures but don’t let them break your main workflow. Implement retry logic with exponential backoff for transient errors.
Batch high-volume events
Batch high-volume events
If you have millions of events per day, pre-aggregate at your backend and send totals every minute rather than sending individual events.
# Instead of: track(quantity=1) for each request
# Do: track(quantity=counter.get_and_reset()) every 60 seconds