PlunkPlunk
API Reference

Track event

Track an event for a contact. Automatically creates or upserts the contact, then records the event. Tracked events can be used as workflow triggers, segment filters, and audience filters.

Reserved event names (rejected with VALIDATION_ERROR and code reserved_event): anything matching email.*, contact.subscribed, contact.unsubscribed, segment.<slug>.entry, segment.<slug>.exit. These are emitted by Plunk itself.

Idempotency: re-tracking the same event creates a new event record. Send an Idempotency-Key header to have a repeated request refused with 409 instead.

POST
/v1/track

Authorization

ApiKeyAuth

AuthorizationBearer <token>

API Key authentication. The project is automatically derived from the key.

/v1/track requires a public key (pk_*) — it is the one endpoint intended for client-side use, and a secret key is rejected there with 401.

Every other endpoint requires a secret key (sk_*) and rejects public keys with 401.

So the two key types are not interchangeable in either direction: pick the key that matches the endpoint you are calling.

In: header

Header Parameters

Idempotency-Key?string

Optional key that guarantees this request runs at most once. If the key was already used by your project, the request is refused with 409 instead of being performed a second time. Keys are scoped to your project, expire after 24 hours (configurable when self-hosting), and must be 1-255 printable ASCII characters.

Lengthlength <= 255

Request Body

application/json

email*string

Contact email. The contact is auto-created if it doesn't exist.

Formatemail
event*string

Event name. Cannot match the reserved patterns above.

subscribed?boolean

Subscription state to apply to the contact. New contacts default to subscribed (true). Existing contacts keep their current state unless you pass an explicit value here. Pass false to track an event without resubscribing an unsubscribed contact.

data?

Contact data and one-off event variables. Persistent values (primitives, plain objects) are saved on the contact and become available as template variables. Pass { value, persistent: false } for one-shot variables that should not be stored on the contact (e.g. order IDs, transaction details). null deletes a field. Empty strings are ignored. Reserved keys are filtered out — see the contacts concept page.

Response Body

application/json

application/json

application/json

application/json

curl -X POST "https://api.plunk.jimster.dev/v1/track" \  -H "Content-Type: application/json" \  -d '{    "email": "user@example.com",    "event": "purchase",    "data": {      "product": "Premium Plan",      "amount": 99    }  }'
{
  "success": true,
  "data": {
    "contact": "string",
    "event": "string",
    "timestamp": "2019-08-24T14:15:22Z"
  }
}
{
  "success": false,
  "error": {
    "code": "INVALID_API_KEY",
    "message": "Invalid secret API key. This endpoint requires a secret key (sk_*), not a public key.",
    "statusCode": 401,
    "requestId": "8f14e45f-ceea-467a-9575-1f0f38e0b1c2"
  },
  "timestamp": "2025-01-15T10:30:00.000Z"
}
{
  "success": false,
  "error": {
    "code": "IDEMPOTENCY_KEY_REUSED",
    "message": "Idempotency-Key \"order-1234-receipt\" has already been used",
    "statusCode": 409,
    "requestId": "8f14e45f-ceea-467a-9575-1f0f38e0b1c2",
    "details": {
      "key": "order-1234-receipt",
      "originalRequest": "POST /v1/send",
      "originalRequestAt": "2025-01-15T10:30:00.000Z",
      "originalStatusCode": 200
    },
    "suggestion": "This Idempotency-Key was already used, so the request was refused rather than performed twice. Generate a new key for a genuinely new request."
  },
  "timestamp": "2025-01-15T10:31:00.000Z"
}
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "statusCode": 422,
    "requestId": "8f14e45f-ceea-467a-9575-1f0f38e0b1c2",
    "errors": [
      {
        "field": "to",
        "message": "Invalid email",
        "code": "invalid_string"
      }
    ],
    "suggestion": "Please check the API documentation for the correct request format."
  },
  "timestamp": "2025-01-15T10:30:00.000Z"
}