### 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.
AI tools
Cursor Rules for Snippet Integrations
Standards and practices for building robust Snippet integrations with Cursor.