Events App —
API Reference.
Schema, endpoints, and call patterns for the Events app. Covers listing events, registering attendees, and checking people in via QR code.
On this page
Overview
The Events app stores event data in two HubSpot custom CRM objects: events and event_registrations. The worksby.design API provides endpoints for listing events, managing registrations, and checking attendees in. Events themselves are created and edited directly in HubSpot CRM (not via this API) — see Managing events below.
Base URL: https://api.worksby.design/apps/events/
All responses are JSON. Successful responses include "success": true. Errors include "error": "<message>" and an appropriate HTTP status code.
fetch-events to list what's available, call fetch-event-details to get attendee counts and details, then call create-registration to register someone. Each call requires portalId — always include it.Authentication
All endpoints except GET /license-status require the portal to have the Events app installed and a valid active license. Authentication is handled automatically — no API key is passed by the caller.
Every request must include portalId — the numeric HubSpot portal ID. For GET requests pass it as a query parameter. For POST requests include it in the JSON body.
The server validates that the portal has completed the OAuth install flow and holds a stored access token. If not, the endpoint returns 403 with { "error": "Portal <id> not authorised for events" }. If the license has expired it returns 403 with { "code": "LICENSE_INACTIVE" }.
Custom Object — events
Created automatically on first install. The name property is unique and acts as the primary identifier across all API calls and navigation links. Object type name: events. The numeric objectTypeId is portal-specific and resolved by the backend at runtime — callers never need it.
events — all properties
| Property | Type | Description |
|---|---|---|
| name | string · unique | Event name. Must be unique per portal. Used as the primary event identifier for URL routing and in fetch-event-details name lookups. Cannot be duplicated. |
| url_slug | string | Legacy URL identifier. Also accepted by fetch-event-details as a lookup key (tried before name). By convention equals a slugified version of name. |
| description | string · textarea | Full event description. Shown on the event detail page. |
| meta_description | string | SEO meta description. Keep under 160 characters. Maps to the HubSpot dynamic page meta description field. |
| highlights | string · textarea | Short bullet-style summary of event highlights. Shown as a callout on event detail pages. |
| start_datetime | datetime | Event start date and time. ISO 8601 format (2026-06-15T09:00:00.000Z). Used as the sort key in fetch-events and the upcoming-only filter. |
| end_datetime | datetime | Event end date and time. ISO 8601 format. |
| event_type | string | Free-text event category. Common values: conference, webinar, workshop, meetup. |
| event_status | enumeration |
Controls visibility. Only published events are returned by fetch-events.
draft
published
cancelled
|
| event_tags | string | Free-text tags for filtering. Semicolon-separated by convention (e.g. training;certification;online). |
| image_featured | string · URL | Full URL to the hero/featured image. Also maps to the HubSpot dynamic page featured image field. |
| image_thumbnail | string · URL | Full URL to the event card thumbnail image. |
| video_featured | string · URL | URL to a featured video (embed URL or direct link). Optional. |
| is_online | boolean |
Whether the event is online-only.
truefalse
|
| location_name | string | Venue name or platform name for online events (e.g. Convention Center Amsterdam, Online via Zoom). |
| street_address | string | Street address of the venue. Leave blank for online events. |
| city | string | City. Leave blank for online events. |
| postal_code | string | Postal/ZIP code. |
| country | string | Country name in full (e.g. Netherlands, Belgium). |
| location_map_type | string | Map provider hint (e.g. google). Optional. |
| location_map_url | string · URL | Embed URL for an interactive map. |
| location_image_map | string · URL | URL to a static map image. |
| price_amount | number | Ticket price. Use 0 for free events. |
| price_currency | string | ISO 4217 currency code (e.g. EUR, USD). |
| payment_link | string · URL | External payment or booking URL (e.g. Stripe, Eventbrite). Optional. |
| ticket_types | string · textarea | Available ticket type names, one per line or semicolon-separated (e.g. standard;vip;student). Used to populate the ticket type selector on the registration form. The ticket_type field on a registration should match one of these values. |
| capacity_total | number | Maximum number of attendees. Set to 0 for unlimited. create-registration blocks new registrations when capacity_current >= capacity_total (and capacity_total > 0). |
| capacity_current | number | Current registration count. Incremented automatically by create-registration. Starts at 0. |
| features | string | Semicolon-separated list of feature/amenity codes shown as icons on event pages. Common values: wifi, parking, food_drinks, networking, certificate, recording, accessible. |
| contact_email | string | Organiser contact email address. Shown on the event detail page. |
| contact_phone | string | Organiser contact phone number. |
| external_url | string · URL | Link to an external event page or additional information. Optional. |
| registration_mode | string | How registrations are collected. Common value: form (inline registration form). Optional — used by the front-end to decide which registration UI to show. |
| requires_membership | boolean |
Whether the event is restricted to members only.
truefalse
|
| meeting_platform | string | Online meeting platform name (e.g. Zoom, Microsoft Teams). Shown when is_online is true. |
| online_meeting_url | string · URL | Direct join URL for the online meeting. Typically shared only after registration. |
| associated_projects | string | Internal field — links the event to a HubSpot Projects record by numeric ID. Events with a value here are hidden when hideProjectEvents: true is passed to fetch-events. |
| training_type | string | Optional classification for training events (e.g. certification, induction). Used by portal-specific filtering logic. |
Custom Object — event_registrations
One record per attendee per event. Created by create-registration. Each registration is associated to its event and (optionally) to a HubSpot contact.
event_registrations — all properties
| Property | Type | Description |
|---|---|---|
| attendee_name | string | Full name (firstName + ' ' + lastName). Set automatically by create-registration. Can be edited via update-registration. |
| first_name | string | Given name. |
| last_name | string | Family name. |
| string | Email address. Used to match or create a HubSpot contact during registration. Editable via update-registration. | |
| phone | string | Phone number. Editable via update-registration. |
| company | string | Company name. Editable via update-registration. |
| job_title | string | Job title. Editable via update-registration. |
| registration_date | datetime | ISO 8601 timestamp of when the registration was created. Set automatically. |
| registration_status | enumeration |
Current status of the registration. checked_in is written programmatically by check-in-by-qr — it is not a declared enum option in the schema but works in HubSpot because the property is a text field under the hood.
confirmed
waitlisted
cancelled
checked_in
|
| ticket_type | string | Ticket type chosen at registration. Defaults to standard if not specified. Should match a value from the event's ticket_types property. |
| qr_code | string | Unique QR check-in code generated at registration time. Format: EVT-XXXXXXXXXXXX (16 chars, uppercase alphanumeric). Used by check-in-by-qr. |
| check_in_datetime | datetime | ISO 8601 timestamp of when the attendee was checked in. Set by check-in-by-qr when action: 'checkin'. |
| payment_status | enumeration |
Payment state. check-in-by-qr grants access when status is free, paid, or complimentary. free and complimentary are non-schema values used programmatically.
pending
paid
refunded
free
complimentary
|
| amount_paid | number | Amount paid in the event's currency. Optional — use for paid registrations. |
| special_requirements | string · textarea | Dietary, accessibility, or other special requirements. Shown on the event attendee list. |
Associations
Three association labels are created automatically on install. Label names are stable contracts — the backend resolves portal-specific numeric type IDs at runtime by matching on the label name. Do not rename these labels in HubSpot.
| From | To | Label | Inverse label |
|---|---|---|---|
| events | event_registrations | Event Registrations | Event |
| contacts | event_registrations | Registered Attendee | Event Registration |
| contacts | events | Registered | Registered Contact |
create-registration creates all three associations automatically. You do not need to create them manually when using this API.Endpoints
Check whether a portal has an active Events license. Does not require OAuth install — safe to call before the install flow.
Query parameters
| Parameter | Type | Description |
|---|---|---|
| portalIdrequired | string | HubSpot portal ID. |
Response
{ "licensed": true }
Return a list of published events, sorted by start_datetime ascending. By default returns only upcoming events (start date in the future).
Request body
| Field | Type | Description |
|---|---|---|
| portalIdrequired | string | HubSpot portal ID. |
| upcomingOnly | boolean | Filter to events whose start_datetime is in the future. Default: true. Pass false to include past events. |
| hideProjectEvents | boolean | If true, exclude events that have a value in associated_projects (used to hide internal project-linked events from public listings). Default: false. |
Response
{
"success": true,
"total": 3,
"events": [
{
"id": "12345678",
"name": "Monthly Member Webinar",
"url_slug": "monthly-member-webinar",
"start_datetime": "2026-06-15T14:00:00.000Z",
"end_datetime": "2026-06-15T16:00:00.000Z",
"event_type": "webinar",
"event_status": "published",
"event_tags": "online;members",
"is_online": "true",
"location_name": "Online via Microsoft Teams",
"city": null,
"country": null,
"price_amount": "0",
"price_currency": "EUR",
"capacity_total": "500",
"capacity_current": "12",
"image_featured": "https://images.unsplash.com/...",
"image_thumbnail": "https://images.unsplash.com/..."
}
]
}
events object properties. Use id when you need to reference this event in other HubSpot CRM API calls; use name when calling fetch-event-details.Fetch full details for a single event including all registered attendees. Looks up the event by url_slug, then name (exact match), then name (partial match) — the first match wins.
Request body
| Field | Type | Description |
|---|---|---|
| portalIdrequired | string | HubSpot portal ID. |
| eventIdrequired | string | Event identifier — can be the url_slug, the exact name, or a partial name. The backend tries each lookup in order until a match is found. |
| isNameLookup | boolean | Pass true when eventId is a decoded event name from a URL path segment. This skips the url_slug lookup and saves one HubSpot API call. Default: false. |
| contactId | string | Optional HubSpot contact ID. Reserved for future use — currently unused by the backend but can be passed without error. |
Response
{
"success": true,
"event": {
"id": "12345678",
"name": "Monthly Member Webinar",
"description": "Our regular online gathering...",
"start_datetime": "2026-06-15T14:00:00.000Z",
"capacity_total": "500",
"capacity_current": "12",
...all event properties...
},
"registrations": [
{
"id": "98765432",
"attendee_name": "Sarah Johnson",
"email": "sarah.johnson@example.com",
"registration_status": "confirmed",
"payment_status": "paid",
"qr_code": "EVT-ABC123DEF456",
"check_in_datetime": null,
...all registration properties...
}
]
}
Find all event IDs that a specific contact is registered for. Matches by contact email address via the event_registrations object.
Request body
| Field | Type | Description |
|---|---|---|
| portalIdrequired | string | HubSpot portal ID. |
| contactIdrequired | string | HubSpot contact ID. The backend fetches the contact's email and uses it to search registrations. |
Response
{
"success": true,
"eventIds": ["12345678", "87654321"]
}
id field returned by fetch-events to determine which events a contact has already registered for.Register an attendee for an event. Creates the event_registrations record, creates or updates the HubSpot contact, and creates all three association links (event → registration, contact → registration, contact → event). Increments capacity_current on the event.
Request body
| Field | Type | Description |
|---|---|---|
| portalIdrequired | string | HubSpot portal ID. |
| eventIdrequired | string | Event identifier — numeric ID from fetch-events, or a url_slug string. Non-numeric values trigger a slug lookup first. |
| formDatarequired | object | Attendee details. See sub-fields below. |
| contactId | string | Optional HubSpot contact ID. If provided, the contact is updated with the form data rather than searched by email. If omitted, the backend searches by email and creates the contact if not found. |
formData fields
| Field | Type | Description |
|---|---|---|
| firstNamerequired | string | Attendee first name. |
| lastNamerequired | string | Attendee last name. |
| emailrequired | string | Attendee email address. Used to find or create the HubSpot contact. |
| phone | string | Phone number. |
| company | string | Company name. |
| jobTitle | string | Job title. |
| ticketType | string | Ticket type. Defaults to standard if not provided. Should match a value from the event's ticket_types field. |
| specialRequirements | string | Dietary, accessibility, or other special requirements. |
Response
{
"success": true,
"registration": {
"id": "98765432",
"qr_code": "EVT-ABC123DEF456",
"email": "sarah.johnson@example.com"
}
}
capacity_total > 0 and capacity_current >= capacity_total, the registration is rejected with 400 { "error": "Event is at full capacity" }. Check capacity before attempting to register.Update a single editable property on an existing registration. Used for inline attendee detail corrections.
Request body
| Field | Type | Description |
|---|---|---|
| portalIdrequired | string | HubSpot portal ID. |
| registrationIdrequired | string | Numeric ID of the event_registrations record. |
| propertyNamerequired | string |
Property to update. Only these five values are accepted:
attendee_name
job_title
company
email
phone
|
| propertyValue | string | New value. Pass an empty string to clear the field. |
Response
{ "success": true }
Look up a registration by QR code and optionally check the attendee in. Returns an access decision that drives the check-in UI: grant entry, deny, flag as already checked in, or report an error.
Request body
| Field | Type | Description |
|---|---|---|
| portalIdrequired | string | HubSpot portal ID. |
| qrCoderequired | string | QR code value from the registration. Format: EVT-XXXXXXXXXXXX. |
| action | string | Pass "checkin" to update the registration to checked_in and record the timestamp. Omit (or any other value) to perform a read-only verification without mutating the record. |
Access decisions
| Decision | Meaning | When |
|---|---|---|
| GRANT | Entry permitted | registration_status is confirmed AND payment_status is free, paid, or complimentary |
| DENY | Entry refused | registration_status is confirmed but payment not cleared, or registration_status is waitlisted or cancelled |
| ALREADY_IN | Already checked in | registration_status is checked_in |
| ERROR | QR code not found | No registration matches the provided QR code (404 response) |
Response
{
"success": true,
"accessDecision": "GRANT",
"checkedIn": true,
"registration": {
"id": "98765432",
"attendeeName": "Sarah Johnson",
"firstName": "Sarah",
"lastName": "Johnson",
"email": "sarah.johnson@example.com",
"company": "Acme Corp",
"jobTitle": "Product Manager",
"ticketType": "standard",
"registrationStatus": "checked_in",
"paymentStatus": "paid",
"checkInDatetime": "2026-06-15T09:32:00.000Z",
"specialRequirements": null
},
"event": {
"name": "Annual Member Conference",
"startDatetime": "2026-06-15T09:00:00.000Z"
}
}
checkedIn is true only when action: "checkin" was passed and the decision was GRANT. On DENY or ALREADY_IN, the record is not modified regardless of the action.Creating and Managing Events
Events are created and edited directly via the HubSpot CRM API — this worksby.design API does not expose a create/update event endpoint. Use the standard HubSpot /crm/v3/objects/{objectTypeId} endpoints with the events custom object.
Resolving the objectTypeId
HubSpot assigns a different numeric objectTypeId to the events custom object on each portal. To resolve it, fetch all schemas and find the one whose name field equals "events":
GET https://api.hubapi.com/crm/v3/schemas
Authorization: Bearer {access_token}
// In the response, find:
results.find(s => s.name === 'events').objectTypeId
// → e.g. "2-12345678"
Creating an event
Once you have the objectTypeId, create an event with a POST to /crm/v3/objects/{objectTypeId}:
POST https://api.hubapi.com/crm/v3/objects/{objectTypeId}
Authorization: Bearer {access_token}
Content-Type: application/json
{
"properties": {
"name": "Monthly Member Webinar",
"url_slug": "monthly-member-webinar",
"description": "Our regular online gathering for members.",
"meta_description": "Free monthly online webinar — live panel and open Q&A.",
"highlights": "Live panel, member updates, exclusive content.",
"event_type": "webinar",
"event_status": "published",
"start_datetime": "2026-07-15T14:00:00.000Z",
"end_datetime": "2026-07-15T16:00:00.000Z",
"is_online": "true",
"location_name": "Online via Microsoft Teams",
"price_amount": "0",
"price_currency": "EUR",
"capacity_total": "500",
"capacity_current": "0",
"features": "recording",
"registration_mode": "form",
"image_featured": "https://images.unsplash.com/photo-...",
"image_thumbnail": "https://images.unsplash.com/photo-..."
}
}
Required properties for a visible event
At minimum, set these properties for an event to appear in fetch-events results:
name— must be unique; this is the event identifierevent_status: "published"— draft and cancelled events are excludedstart_datetime— must be in the future (unlessupcomingOnly: false)
Updating an event
PATCH https://api.hubapi.com/crm/v3/objects/{objectTypeId}/{eventId}
Authorization: Bearer {access_token}
Content-Type: application/json
{
"properties": {
"event_status": "cancelled"
}
}
name property has a unique constraint. Attempting to create two events with the same name on the same portal will fail with a HubSpot 409 conflict error. If you need test events, use distinct names.