API
Programmatic access to ingest events and manage customer and subscription data.
Authentication
All API requests require an API key sent via the Authorization header:
Authorization: Bearer your_api_key_here
Generate API keys from your workspace settings. Keys are scoped to a workspace and grant access to all sites within it. Treat them like passwords — never expose them in client-side code.
Base URL
https://www.abner.app
POST /api/ingest/
Ingest a pageview event. This is the same endpoint used by the tracking script, but you can call it directly for server-side tracking.
POST /api/ingest/
Content-Type: application/json
{
"site_id": "your_site_id",
"url": "https://example.com/page",
"referrer": "https://google.com",
"screen_width": 1920
}
Fields:
| Field | Type | Required | Description |
|---|---|---|---|
| site_id | string | Yes | Your site identifier |
| url | string | Yes | Full page URL |
| referrer | string | No | Referrer URL |
| screen_width | integer | No | Visitor's screen width in pixels |
Returns 202 Accepted on success.
POST /api/v1/customers/
Create or update a customer record for SaaS metrics. If a customer with the same external_id exists, it will be updated.
POST /api/v1/customers/
Authorization: Bearer your_api_key_here
Content-Type: application/json
{
"external_id": "cus_abc123",
"email": "customer@example.com",
"name": "Jane Doe",
"created_at": "2025-06-15T10:30:00Z"
}
| Field | Type | Required | Description |
|---|---|---|---|
| external_id | string | Yes | Unique identifier from your system |
| string | No | Customer email | |
| name | string | No | Customer name |
| created_at | ISO 8601 | No | When the customer was created |
Returns 201 Created or 200 OK (if updated).
POST /api/v1/subscriptions/
Create or update a subscription record. Links to a customer via customer_external_id.
POST /api/v1/subscriptions/
Authorization: Bearer your_api_key_here
Content-Type: application/json
{
"external_id": "sub_xyz789",
"customer_external_id": "cus_abc123",
"status": "active",
"plan_name": "Pro",
"amount_cents": 4900,
"currency": "usd",
"interval": "month",
"current_period_start": "2026-02-01T00:00:00Z",
"current_period_end": "2026-03-01T00:00:00Z"
}
| Field | Type | Required | Description |
|---|---|---|---|
| external_id | string | Yes | Unique subscription identifier |
| customer_external_id | string | Yes | Links to a customer record |
| status | string | Yes | active, canceled, past_due, trialing |
| plan_name | string | No | Name of the plan |
| amount_cents | integer | Yes | Price in cents (e.g., 4900 = $49.00) |
| currency | string | No | ISO currency code (default: usd) |
| interval | string | Yes | month or year |
| current_period_start | ISO 8601 | No | Start of current billing period |
| current_period_end | ISO 8601 | No | End of current billing period |
Returns 201 Created or 200 OK (if updated).
Rate limits
API requests are rate-limited to 100 requests per second per API key. The ingest endpoint (/api/ingest/) has a higher limit of 1,000 requests per second per site. If you exceed the limit, you'll receive a 429 Too Many Requests response.
Error responses
Errors return a JSON object with a detail field:
{
"detail": "Invalid API key."
}
Common status codes:
400— Invalid request body401— Missing or invalid API key404— Resource not found429— Rate limit exceeded