Conventions
Cross-cutting rules that apply across all Animo API v1 endpoints.Base URL and versioning
- All endpoints are prefixed with
/api/v1. - Versioning is URL-based only. There is no
Acceptheader versioning. - Future versions would use a new prefix (e.g.
/api/v2).
Identifiers
Public identifiers in API responses are not database primary keys:| Resource | ID format | Example field |
|---|---|---|
| User | sqid | id |
| Company | sqid | id (path param {company}) |
| Event | slug | id (path param {event}) |
| Activation | slug | id |
| Form | sqid | id |
| Form field | sqid | id |
| Order | sqid | id |
| Cohost | sqid | id |
| Ticket type | slug | slug |
| Webhook | UUID | id |
id (or slug for ticket types) returned by the API in subsequent requests. Route model binding resolves these public identifiers automatically.
Timestamps
Datetime fields in responses use ISO 8601 with a+00:00 offset. See Timestamps (actual format) for the real shape — do not assume a Z suffix or fixed millisecond width.
Input format for event dates (create/update) uses a separate format: Y-m-d H:i (e.g. 2026-04-25 09:00).
Pagination
List endpoints return Laravel’s standard paginated JSON:page query parameter to navigate.
Company context
Most resources are scoped under a company:{company}is the company sqid fromGET /api/v1/companies.- Middleware restricts all queries to that company.
- The authenticated user must belong to the company.
- The company must have an active Pro plan (enforced via the
USE_APIsubscription gate).
Subscription gates
API access is a paid feature. In the Animo admin, this is the Pro plan. Subscribe or upgrade at https://app.animo.co/admin/settings/billing.| Internal gate | Animo plan | Required for |
|---|---|---|
USE_API | Pro (Stripe tier: starter) | All company-scoped REST resources (events, forms, orders, etc.) |
USE_INTEGRATIONS | Pro and above | Webhook attach/update/detach |
Entitlement behavior
| Endpoint | Without Pro plan |
|---|---|
GET /api/v1/companies | 200 with empty data: [] — looks like “no companies”, not a permission error |
GET /api/v1/{company}/… (and other company-scoped routes) | 403 Forbidden |
GET /companies returns an empty list, check the company’s plan before debugging scopes or token setup.
Public URLs
The API does not return public-facing URLs in responses today. Construct them from slugs in the API response.Event page
| Segment | API source |
|---|---|
{company-slug} | slug from GET /api/v1/companies |
{event-slug} | id from event resources |
Ticket signup page
Ticket types created via the API can be linked on the public Animo ticket shop. These URLs are separate from the API base URL and use slugs, not sqids. Pattern:| Segment | Source | API field |
|---|---|---|
{company-slug} | Company URL slug | slug on GET /api/v1/companies |
{event-slug} | Event URL slug | id on event resources |
{ticket-type-slug} | Ticket type slug | slug on ticket type resources |
| Parameter | Description |
|---|---|
qty | Pre-select ticket quantity on the signup page (e.g. ?qty=1) |
/form on the same path when a registration form is attached to the ticket type.
Order checkout page (paid tickets)
After creating a paid order via the API, send the attendee to Mollie checkout:| Segment | API source |
|---|---|
{order-id} | id from the order resource (sqid) |
paid_at remains null until Mollie payment succeeds (async webhook).
Activation form page
To embed or link an Animo-hosted activation form (sponsorship, waitlist, contact) from a custom site, get the activationslug from GET /api/v1/{company}/activations. There are two URL variants. Prefer the company-scoped URL by default — it always works for published activations. Use the event-scoped form only when you need to attribute the signup to a specific event.
Company-scoped (default):
| Segment | API source |
|---|---|
{company-slug} | slug from GET /api/v1/companies |
{activation-slug} | id or slug from GET /api/v1/{company}/activations |
{event-slug} | id from the linked event (not returned on ActivationResource — see below) |
Unlike tickets, event activations do not useSub-paths (the flow, same as tickets): the base URLs above are the entry point./event/in the path — it’s/{company}/{event}/{activation}, not/{company}/event/{event}/{activation}.
/form (form step) and /thank-you (confirmation) are reached after sign-up — link cold traffic to the base URL, not /form; visitors who hit /form without signing up are redirected back to the base URL. An event-scoped URL whose activation isn’t actually attached to that event also redirects to the company-scoped URL.
API gap: ActivationResource does not expose the linked event’s slug, so you can’t build the event-scoped URL from GET /activations alone — fetch the event slug from GET /events, or use the company-scoped URL, which always works.
Slug behavior (events vs ticket types)
| Resource | On create | On update |
|---|---|---|
| Event | id/slug derived from name — supplied slug is ignored | slug can be changed via PATCH |
| Ticket type | Supplied slug is honored | slug can be changed via PATCH |
Timestamps (actual format)
Responses use ISO 8601 datetimes with a+00:00 UTC offset, not a Z suffix:
.4040, .011, .088). Do not assume exactly three millisecond digits. Parse as ISO 8601 with flexible fractional seconds.
Search filter
Several list endpoints support aq query parameter for case-sensitive substring search:
| Endpoint | Searches |
|---|---|
GET /api/v1/{company}/activations | title |
GET /api/v1/{company}/events | name |
GET /api/v1/{company}/forms | name |
Optional includes
| Query parameter | Endpoints | Effect |
|---|---|---|
include_form | Ticket type list/show | Embeds the related form and fields |
include_submission | Order list/show | Embeds submission (with form and answers) and lead |
Request bodies
- Send JSON with
Content-Type: application/json. PATCHendpoints accept partial updates — only include fields you want to change.POSTcreate endpoints use paths like/create(e.g.POST /api/v1/{company}/events/create).
Validation errors
Invalid request bodies return422 Unprocessable Entity:
Response envelope
Single resources are wrapped in adata key: