Copy
### Snippet Custom Integrations - Cursor Rules
These rules guide developers to implement robust, consistent custom integrations for Snippet widgets.
#### 1) Core conventions
- **One protocol = one widget**: Each widget maps to a unique `protocolId` (slug).
- **Unique IDs**: Choose a lowercase, hyphen/underscore-only slug for `protocolId` (e.g., `awesome-dex`). The server sanitizes invalid characters to `-`.
- **Metric ID format**: `{protocolId}___{Label}` (triple underscore). Examples: `awesome-dex___TVL`, `awesome-dex___USERS_MOM`.
- **Label length**: Keep `{Label}` ≤ 16 chars for best widget legibility.
- **Units**: Free-form (e.g., `USD`, `%`, `BTC`, `TPS`, `football_fields`). Keep units consistent per metric `id`.
#### 2) Authentication and environments
- **Auth header** (required for write, optional for reads of private data):
- `Authorization: Bearer <SNIPPET_API_KEY>`
- **Environment variables** (recommended):
- `SNIPPET_API_BASE=https://<your-api-host>`
- `SNIPPET_API_KEY=sk_snippet.gg...` (from the Snippet mobile app)
#### 3) Protocol registration rules
- Register once per `protocolId`:
- `POST /api/register-protocol` with `{ id, name, logo?, chains? }`
- On `400` id conflict, pick a new slug or query availability via `GET /api/validate-protocol?id=...`.
- Treat `id` as immutable after creation to avoid breaking existing widgets.
#### 4) Metric submission rules
- Endpoint: `POST /api/metrics`
- Body shape: `{ metrics: Array<{ id, value, protocolId, unit?, module?, timestamp? }> }`
- Required fields per metric: `id`, `value`, `protocolId`
- Optional fields:
- `unit` (free-form)
- `module` (defaults to `"protocol"`)
- `timestamp` (ISO 8601). If provided, it is used as-is; if omitted, the server snaps to the top of the hour. Must not be > 5 minutes in the future.
- Batching: Max 100 metrics per request.
- Ownership: You can only write to protocols owned by your API key (or public protocols).
- Posting cadence (recommendation): At most once per hour per metric `id` to align with widget display.
#### 5) Reading metrics (widget consumption)
- Public data: `GET /metrics/byProtocol/:protocolId` (no auth needed).
- Private data (owned by your key): include the same `Authorization` header.
- Response includes current value, change fields (`change1h`, `change24h`), `unit`, and `timestamp` per metric.
#### 6) Error handling and retries
- Common statuses:
- `400` invalid request (do not retry; fix payload)
- `401` invalid key (do not retry; fix auth)
- `404` protocol not found (ensure registration)
- `5xx` server errors (retry with exponential backoff)
- Retry policy (recommended): exponential backoff with jitter, max 5 attempts; stop on 4xx except `429`.
- Capture and surface response `warnings` from metric submission (e.g., long labels, updates to existing metrics).
#### 7) Validation checklist (pre-deploy)
- Validate API key: `GET /api/validate-key`
- Validate protocol availability: `GET /api/validate-protocol?id=<protocolId>`
- Ensure all `metrics[].id` follow `{protocolId}___{Label}`
- Ensure timestamps are ISO 8601 and ≤ 5 minutes in the future (if provided)
- Confirm batch sizes ≤ 100 and stable `unit` usage per metric `id`
- Manually test reads: `GET /metrics/byProtocol/<protocolId>` (with/without auth depending on visibility)
#### 8) Security rules
- Store secrets only in environment variables or a secure vault.
- Never log full API keys or sensitive payloads.
- Use HTTPS for all endpoints.
- Rotate keys on compromise; validate with `GET /api/validate-key` after rotation.
#### 9) Observability and quality
- Log request IDs and error messages from API failures where available.
- Include metric `id` and `protocolId` in logs for traceability (avoid sensitive values).
- Add unit tests for ID formatting and timestamp logic.
- Alert on repeated `4xx` (payload issues) and `5xx` (service/infra).
#### 10) Sample submission (cURL)
```bash
curl -X POST "$SNIPPET_API_BASE/api/metrics" \
-H "Authorization: Bearer $SNIPPET_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"metrics": [
{
"id": "awesome-dex___TVL",
"value": 12345678.9,
"protocolId": "awesome-dex",
"unit": "USD",
"timestamp": "2025-08-05T17:00:00Z"
},
{
"id": "awesome-dex___USERS_MOM",
"value": 5.2,
"protocolId": "awesome-dex",
"unit": "%"
}
]
}'
```
#### 11) Minimal TypeScript helper (Node/Bun)
```ts
const base = process.env.SNIPPET_API_BASE!;
const key = process.env.SNIPPET_API_KEY!;
export async function pushMetrics(
metrics: Array<{
id: string;
value: number;
protocolId: string;
unit?: string;
module?: string;
timestamp?: string; // ISO 8601
}>
) {
const res = await fetch(`${base}/api/metrics`, {
method: "POST",
headers: {
Authorization: `Bearer ${key}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ metrics }),
});
if (!res.ok) {
const text = await res.text();
throw new Error(`Push failed (${res.status}): ${text}`);
}
return res.json();
}
```
#### 12) Do/Don't
- Do: Keep `{Label}` concise and stable; use consistent units; guard against clock skew (>5 min future).
- Do: Validate protocol availability before creating; handle id conflicts gracefully.
- Don't: Change `protocolId` after launch; exceed 100 metrics per batch; log secrets.
These rules align with the Snippet public API: register a protocol, push metrics, and read them for widget display with consistent timestamp handling and flexible units.