Eventro Platform API
Integrate event management, ticket inventory, server-authoritative Paystack payments, and real-time signed webhooks directly into your website or custom apps.
Overview & Architecture
The Eventro API is organized around REST conventions. All requests use standard HTTP methods, return JSON with standardized envelopes, enforce strict origin and body constraints, and provide public prefixed IDs (evt_..., tkt_..., reg_..., whe_...) so internal database sequences are never exposed.
https://eventro.africa/api/v1
application/json (UTF-8)
Bearer <token>
Authentication & API Keys
Every API request must include an HTTP Authorization header containing your integration secret token. Organization tokens begin with an environment prefix:
evt_live_...: Live production mode (charges real cards via Paystack).evt_test_...: Test / sandbox mode (allows simulation without payment gateways).
-H "Authorization: Bearer evt_live_abc123..."
Key Rotation: Eventro supports zero-downtime key rotation with grace periods. When you rotate a key from your organization developer settings, the previous key remains valid for up to 72 hours before automatic expiry.
Permission Scopes
Integrations can be restricted to minimal scopes to protect attendee data:
| Scope | Grants |
|---|---|
| events:read | List and read event details and aggregate ticket statistics. |
| events:write | Create, update, and upload event banners. |
| events:publish | Publish, unpublish, and cancel events. |
| tickets:read / tickets:write | Create and configure paid, free, or donation ticket types and limits. |
| registrations:read | List orders and attendee records. PII (phone/email) gated to authorized callers. |
| registrations:write | Reserve tickets and create attendee orders. |
| attendees:check_in | Check in attendees and fetch ticket barcode QR SVG graphics. |
| payments:read | Verify Paystack transactions and inspect payment statuses. |
| webhooks:read / webhooks:write | Manage webhook endpoints, rotate signing keys, and trigger redeliveries. |
Idempotency & Replays
All mutating endpoints (POST /registrations, POST /payment) support the Idempotency-Key header. Sending the same key within 24 hours replays the exact original response without duplicate charges or duplicate inventory reservations:
-H "Authorization: Bearer evt_live_..." \
-H "Idempotency-Key: a4c89db1-331e-4509-9fc6-c4d6f8319f39" \
-d '{"registration":{"ticket_type_id":"tkt_123","attendee_first_name":"Jane","attendee_email":"jane@example.com","quantity":1}}'
Rate Limits
API endpoints enforce per-minute sliding limits and daily quotas. Every response includes rate-limit headers:
Error Handling
Errors always return standard HTTP error status codes with structured JSON bodies:
"error": "Validation failed: Price must be greater than or equal to 0",
"code": "validation_failed",
"type": "invalid_request_error",
"details": [
{ "field": "price", "code": "greater_than_or_equal_to", "message": "Price must be greater than or equal to 0" }
],
"request_id": "req_97df8ca0b1..."
}
Events Management
Complete lifecycle operations for creating, drafting, publishing, cancelling, and duplicating events:
/api/v1/events
List events for your organization. Supports status filtering: ?status=published|draft|past|upcoming.
/api/v1/events
Create a new event in draft mode. The body is wrapped as {"event": {...}} with name, category_id, event_start_date, event_location, tags and more. Send banner artwork as event.image_data_uri (base64 data URI) or a multipart event[image] file. Returns the Event object.
/api/v1/events/:id/publish
Validates dates, banner artwork, and ticket configuration before transitioning event to published state.
/api/v1/events/:id/cancel
Cancels event and halts further ticket sales.
Public Events (Catalog)
Unauthenticated, high-performance cached endpoints for public websites, apps, and ticket widgets. Caller keys are not required.
/api/v1/public/events
Browse the public catalog of live, published events. Filter by category, organization, or date range.
/api/v1/public/events/:slug_or_id
Returns published event info (including url, the public event page), on-sale tickets, and remaining capacity. Cached with HTTP ETag headers.
Ticket Types & Inventory
Configure admission categories (paid, free, donation), set sales windows, enforce min/max order quantity, and monitor real-time availability.
/api/v1/events/:event_id/ticket_types
Paginated list ({"object":"list","data":[...],"meta":{...}}) of ticket types with inventory metrics: total quantity, tickets sold, and remaining available capacity.
/api/v1/events/:event_id/ticket_types
Create a new ticket type. The body is wrapped as {"ticket_type": {...}} and accepts type (paid, free, donation), name, price, quantity, min_per_order, max_per_order, sale_starts_at, and sale_ends_at. Prices are numbers in the main currency unit (NGN, not kobo).
/api/v1/ticket_types/:id
Update ticket parameters. Note: Once tickets have been sold, commercial pricing is frozen for integrity. Capacity may only be increased.
/api/v1/ticket_types/:id/archive
Safely archives ticket type from public view without deleting past order history.
Orders & Registrations
Reserve tickets and manage attendee registration data. Registrations use a two-step checkout model to prevent overselling:
/api/v1/events/:event_id/registrations
Creates an order and reserves ticket capacity for 15 minutes. If payment is not completed before expires_at, inventory automatically returns to the available pool.
"registration": {
"ticket_type_id": "tkt_123",
"attendee_first_name": "Jane",
"attendee_last_name": "Doe",
"attendee_email": "jane@example.com",
"quantity": 1
}
}
/api/v1/events/:event_id/registrations
Paginated list ({"object":"list","data":[...],"meta":{...}}) of registrations for an event. Filter by status (confirmed, pending_payment, cancelled) or check-in state.
/api/v1/registrations/:id
Update attendee contact information (name, email, phone) on an active order.
Attendee Check-In & Admission QR
Eventro automatically generates secure barcodes and SVG QR graphics for confirmed attendees, fully compatible with the Eventro onsite ticket scanner.
/api/v1/registrations/:id/ticket
Returns the attendee admission credential, ticket reference code, check-in status, and the raw qr_code_svg vector graphic for rendering directly in your mobile app or custom badge.
/api/v1/registrations/:id/ticket.pdf
Downloads the official Eventro printable PDF admission ticket badge.
/api/v1/registrations/:id/check_in
Admit attendee at event gate. Records timestamp and marks record as checked in. Idempotent: repeated calls indicate whether attendee was already admitted.
/api/v1/registrations/:id/undo_check_in
Reverses accidental check-in and resets admission status.
Server-Authoritative Paystack Checkout
Ticket pricing and fees are strictly calculated on Eventro servers. Third-party clients never submit raw prices.
-
Reserve Order:
POST /api/v1/events/:event_id/registrationscreates a pending reservation and locks inventory for 15 minutes. -
Initialize Payment:
POST /api/v1/registrations/:id/paymentreturns a Paystack authorization URL:{
"object": "payment_session",
"authorization_url": "https://checkout.paystack.com/access_code_123",
"reference": "TXN-8B2F..."
} -
Verify Confirmation: Once the customer completes checkout on Paystack, call
POST /api/v1/registrations/:id/payment/verifyto confirm the transaction and issue tickets.
Test Mode & Simulation
Events created with sandbox: true allow developers to test complete booking flows without contacting live payment processors:
-H "Authorization: Bearer evt_test_..." \
-d '{"outcome":"success"}'
Response Shapes & Conventions
- Money: all amounts are JSON numbers in the main currency unit (
2500.0= NGN 2,500.00, not kobo).currencyis always"NGN". - Lists:
{"object":"list","data":[...],"meta":{"page","per_page","total_count","total_pages","has_more"}}. Pagination is also in theX-Total-CountandLinkheaders. - Public event page: use the event's
urlfield (shapedhttps://eventro.africa/events/<id>-<slug>); don't build it yourself. - Request bodies are wrapped under
event,ticket_typeorregistration.
Ticket type
{
"id": "tkt_abc123", "object": "ticket_type", "type": "paid",
"name": "Regular", "price": 2500.0, "currency": "NGN",
"effective_price": 2500.0, "early_bird_active": false,
"quantity": 100, "remaining": 87, "sold_out": false, "on_sale": true,
"sale_starts_at": null, "sale_ends_at": "2026-12-01T18:00:00Z",
"min_per_order": 1, "max_per_order": 10,
"enabled": true, "archived": false, "event_id": "evt_abc",
"inventory": { "total": 100, "sold": 10, "reserved": 3, "remaining": 87 }
}Registration (order)
{
"id": "reg_abc123", "object": "registration",
"event_id": "evt_abc", "ticket_type_id": "tkt_abc123",
"status": "pending_payment", "payment_status": "unpaid", "quantity": 1,
"amount": { "subtotal": 2500.0, "fees": 125.0, "total": 2625.0, "currency": "NGN" },
"payment_reference": null, "ticket_code": null,
"checked_in": false, "expires_at": "2026-10-15T10:30:00Z",
"attendee": { "first_name": "Jane", "last_name": "Doe", "email": "jane@example.com", "phone": null },
"payment_required": true,
"next_action": "POST /api/v1/registrations/reg_abc123/payment"
}The last two fields appear only in the create response. attendee is omitted for keys without PII access.
Webhooks & Event Delivery
Receive real-time signed HTTP POST notifications whenever events, tickets, registrations, or payments change.
Supported Event Types
Payload Format
Each delivery is a JSON POST with headers Eventro-Event-Id, Eventro-Event-Type, Eventro-Delivery-Id and Eventro-Delivery-Attempt. The envelope id is identical across retries and redeliveries, so use it to de-duplicate. Payloads are deliberately minimal (no attendee personal data); fetch details through the API with the ids provided.
{
"id": "whevt_abc123",
"type": "payment.succeeded",
"api_version": "v1",
"created_at": "2026-10-15T10:20:00Z",
"livemode": false,
"data": {
"object": {
"id": "reg_abc123", "object": "registration",
"event_id": "evt_abc", "ticket_type_id": "tkt_abc123",
"status": "confirmed", "payment_status": "paid", "quantity": 1,
"amount": 2625.0, "currency": "NGN",
"payment_reference": "ref_123", "ticket_code": "A1B2C3",
"checked_in": false
}
}
}Registration objects here use a flat amount (total, main currency unit), unlike the nested amount in the API object. ticket_code is only present on ticket.* and payment.succeeded. Event and ticket_type events carry data.object with "object": "event" / "ticket_type".
Verifying Webhook Signatures
Every webhook delivery includes the Eventro-Signature header formatted as t=<timestamp>,v1=<signature>. Calculate the HMAC-SHA256 signature using your endpoint's signing secret and verify it matches within 5 minutes:
def verify_eventro_signature(raw_payload, signature_header, signing_secret)
parts = signature_header.split(",").to_h { |p| p.split("=", 2) }
timestamp = parts["t"].to_i
return false if (Time.now.to_i - timestamp).abs > 300
expected = OpenSSL::HMAC.hexdigest("SHA256", signing_secret, "#{timestamp}.#{raw_payload}")
Rack::Utils.secure_compare(expected, parts["v1"])
end
function verifyEventroSignature(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(signatureHeader.split(",").map(p => p.split("=")));
const timestamp = parseInt(parts.t, 10);
if (Math.abs(Math.floor(Date.now() / 1000) - timestamp) > 300) return false;
const expected = crypto.createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}