Events API
POST /events/create
The single endpoint behind every Solary integration: track an event, resolve the shopper, and create a point transaction.
Request
http
POST /v1/events/create
Host: portal.solary.app/api
Content-Type: application/json
X-API-Key: YOUR_API_KEY
{
"eventType": "purchase_completed",
"email": "shopper@example.com",
"firstname": "Jane",
"lastname": "Doe",
"pointsEarned": 2000,
"type": "earn",
"metadata": { "orderId": "12345" }
}Headers
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your company's API key. Identifies which company the event belongs to. |
Content-Type | Yes | application/json |
Body
| Field | Type | Required | Description |
|---|---|---|---|
eventType | string | Yes | Free-form event name, e.g. purchase_completed, signup_completed. |
pointsEarned | number | Yes | How many points to earn, redeem, or adjust. |
email | string | One of email/userId | Identifies the shopper. If no Solary user exists yet for this email, one is created automatically and linked to your company. |
userId | number | One of email/userId | The shopper's internal Solary user id, if you already know it. |
firstname | string | No | Used only when a new user is created from email. |
lastname | string | No | Used only when a new user is created from email. |
type | earn | redeem | adjustment | No | Defaults to earn. |
metadata | object | No | Arbitrary data attached to the transaction, e.g. an order id. |
Identity resolution
You must provide either
email or userId. Using email is the recommended path for platform integrations: Solary looks up the user by email, and if none exists yet, creates one automatically and links it to your company, no signup flow required on your end.Response
On success, the endpoint returns the created point transaction.
201 Created
{
"statusCode": 201,
"data": {
"id": 6,
"createdAt": "2026-07-31T21:43:49.176Z",
"updatedAt": "2026-07-31T21:43:49.176Z",
"deletedAt": null,
"userId": 4,
"companyId": 1,
"points": 2000,
"type": "earn",
"reason": "External event: purchase_completed",
"source": "external_api",
"status": "fulfilled",
"metadata": { "eventType": "purchase_completed", "orderId": "12345" }
}
}On failure, it returns an error envelope with a human-readable message.
401 Unauthorized
{
"errorId": "63e3001b-a1b3-456c-954a-c13ca97f06a9",
"statusCode": 401,
"timestamp": "2026-07-31T21:44:13.000Z",
"path": "/v1/events/create",
"data": { "errors": "Invalid or inactive API key" }
}Status codes
| Status | Meaning |
|---|---|
201 | Transaction created. |
400 | Missing or invalid fields, e.g. neither email nor userId provided. |
401 | Missing, invalid, or revoked API key. |
404 | userId was provided but doesn't match an existing user. |
429 / 5xx | Retry with backoff. All server SDKs do this automatically. |
Ready to call this from your language of choice? See the server SDKs, or the platform integrations if you'd rather not write any code.