# Vinktar > Vinktar is a product analytics platform with error tracking built in: send > events and errors from your app, then explore them as trends, funnels, > dashboards and an issue list. Events are sent to the ingest endpoint with a > project write key (`vnk_pk_…`). ## Setup - [Vinktar setup skill](/skill.md): An installable agent skill (`npx skills add https://vinktar.com/skill.md`) that wires Vinktar into an app: send a first event over the HTTP API, link identity, hook up error tracking (including via a Sentry SDK's DSN), and verify data is actually flowing. Start here to instrument an app. - [Wire contract](/api.md): The full ingest API reference. Endpoints, auth, payload shapes, every limit and status code. What SDK authors integrate against. ## Ingest - Endpoint: `POST https://in.vinktar.com/v1/batch` - Auth header: `X-Vinktar-Key: vnk_pk_…` (a `write`-scoped key; a `read` key returns `403 write_scope_required`) - Body: `{ "batch": [{ "name": "Signed up", "user_id": "user_123", "payload": { "plan": "pro" } }] }` - Success is not the 202. Assert the body: `rejected` is 0, `errors` is empty, `received` equals what you sent, and no `identify_ignored` key. `received` counts accepted events plus every identify entry, including ones the same response reports as ignored. - `payload` vs `context`: `payload` is free-form properties; `context` is a fixed set of well-known keys (`current_url`, `referrer`, `utm_*`, `os`, `browser`) that land in typed columns and drive the fast filters. URL and campaign data belongs in `context`. - Identity: two ids. `device_id` is the device, `user_id` is the person. Send both on an `identify` entry to link them; because identity resolves at query time, the person's prior anonymous activity joins their history retroactively. First link wins, so call reset (a fresh `device_id`) on logout. - User traits: `identify` also takes `$set` (last write wins), `$set_once` (first write wins, for signup date / first referrer) and `$unset`. These ARE stored and queryable as `user.` in the SQL editor and as dashboard filters. Reserved traits are `$`-prefixed (`$email`, `$name`, `$username`, `$avatar`, `$created`); bare spellings are accepted and normalised. Flat scalars only, 255 bytes per value. - Traits with no event attached: `POST /v1/identify`. - Errors: `POST /v1/errors`, or point any Sentry SDK at `https://@in.vinktar.com/` (Sentry-compatible envelope endpoint; transactions/sessions/replays are acknowledged and discarded). The `/v1/errors` response also carries `suppressed`: an inbound filter drops the usual browser noise, so `received: 0` there is not a broken key. ## SDKs Official SDKs (`@vinktar/browser`, `@vinktar/node` on npm; `vinktar/php`, `vinktar/symfony` on Packagist) are being published language by language and are **not on their registries yet**. Do not install or import them. Integrate over the HTTP API per [/skill.md](/skill.md); it is the same contract the SDKs use. ## Key rules - Event names are case-sensitive; pick one convention and keep it consistent. - Send numeric properties as numbers, not strings, so they can be aggregated. - Never build event names dynamically; put the variable part in a property. - Use a stable user id (a database id), never an email. - Do not honour `Retry-After` blindly on a `429`: the monthly-cap codes set it to the first of next month. - There is no `/v1/flags` endpoint and no feature-flags product.