Developer documentation · API version 2026-09-28

Build on Valore

A REST API for everything on your calendar: events, guests, tickets, orders, subscribers and your team. Signed webhooks tell you the moment something happens, and the MCP server lets Claude, Cursor and other assistants work on your events directly.

Base URL
https://valore.app/api/v1
Authentication
Authorization: Bearer vlr_…
Format

JSON, snake_case, UTC timestamps, integer cents.

Getting started

Introduction

Every API key belongs to one calendar, which is Valore's organization unit: a brand, community or team that publishes events. A key sees only that calendar's events, guests and subscribers, and acts as the person who created it. Owners and admins can create keys from Settings → Developers.

REST API

Create events, manage guests and tickets, sync subscribers. Predictable resources, cursor pagination.

Webhooks

Signed HTTPS callbacks for registrations, check-ins, payments and more, retried automatically.

MCP server

Give AI assistants the same powers through the Model Context Protocol, scoped by the same keys.

Send your key as a bearer token on every request. Keys start with vlr_ and are shown once when created; only a hash is stored. Choose read-only when a key only needs to read data: it can call GET endpoints and read-only MCP tools, and nothing else. Revoking a key takes effect immediately.

header
Authorization: Bearer vlr_a1b2c3d4e5f6…

Keep keys server-side. Browsers may call GET endpoints (CORS is enabled), but a key in client code is a key anyone can copy.

  1. Create a key in Settings → Developers for the calendar you want to work with.
  2. List your published events:
export VALORE_API_KEY=vlr_…

curl "https://valore.app/api/v1/events?status=published&limit=5" \
  -H "Authorization: Bearer $VALORE_API_KEY"
  1. Create an event with POST /events, add people with POST /events/:id/guests, and register a webhook to hear about new registrations.
  • Bodies are JSON with Content-Type: application/json. Field names are snake_case; enums are lowercase strings (going, in_person).
  • Single objects come back as { data: {…} }; lists as { data: […], next_cursor }.
  • Timestamps are ISO 8601 in UTC. When creating or updating events you may also send a wall-clock time like 2026-11-05T18:00, interpreted in the event's timezone.
  • Money is integer cents (price_cents: 2500 is $25.00) in the event's currency.
  • PATCH is partial: send only the fields that change. Sending null clears a nullable field.
  • Every response carries X-Request-Id. Include it when you contact support about a request.

Errors use conventional HTTP status codes and a JSON body of the shape { "error": "message" }. Validation messages name the field: starts_at: Invalid date.

400Invalid input. The message names the field, e.g. starts_at: Invalid date.
401Missing, revoked or malformed API key.
403The key is read-only, or the action needs a role the key's owner doesn't have.
404The resource doesn't exist or belongs to another calendar.
409Conflict with current state, e.g. deleting an event that has paid guests.
429Rate limit exceeded. Wait for Retry-After seconds.
500Something went wrong on our side. Retry with backoff; include X-Request-Id when reporting it.

List endpoints return up to limit items (default 25, max 100) and a next_cursor. Pass it back as ?cursor= to fetch the next page; it's null on the last page. Cursors are stable across inserts, so you won't skip or repeat rows while paging.

Node.js · walk every page
let cursor = null;
do {
  const url = new URL("https://valore.app/api/v1/events/EVENT_ID/guests");
  url.searchParams.set("limit", "100");
  if (cursor) url.searchParams.set("cursor", cursor);
  const page = await fetch(url, { headers }).then((r) => r.json());
  for (const guest of page.data) process(guest);
  cursor = page.next_cursor;
} while (cursor);

Each key may make 300 requests per minute. Every response includes X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix seconds). Over the limit you get 429 with a Retry-After header. Bulk endpoints (add guests, invite, import subscribers) accept hundreds of rows per call, so prefer them over loops.

Reference

Resources

All paths are relative to https://valore.app/api/v1. Examples use placeholder ids; every id you need comes back from a list or create call.

GET/me
GET/calendar
PATCH/calendar
GET/brand-themes
GET/events
POST/events
GET/events/:id
PATCH/events/:id
POST/events/:id/publish
POST/events/:id/duplicate
DELETE/events/:id
GET/events/:id/insights
GET/events/:id/guests
GET/guests
GET/attendees
POST/events/:id/guests
GET/guests/:id
PATCH/guests/:id
POST/guests/:id/check-in
DELETE/guests/:id
GET/events/:id/invites
POST/events/:id/invites
POST/events/:id/invites/check
GET/events/:id/hosts
POST/events/:id/hosts
DELETE/events/:id/hosts/:hostId
GET/events/:id/ticket-types
POST/events/:id/ticket-types
GET/ticket-types/:id
PATCH/ticket-types/:id
DELETE/ticket-types/:id
GET/events/:id/coupons
POST/events/:id/coupons
GET/coupons/:id
PATCH/coupons/:id
DELETE/coupons/:id
GET/events/:id/questions
POST/events/:id/questions
GET/questions/:id
PATCH/questions/:id
DELETE/questions/:id
GET/events/:id/orders
GET/orders/:id
POST/orders/:id/refund
GET/events/:id/feedback
GET/events/:id/photos
PATCH/photos/:id
DELETE/photos/:id
GET/events/:id/tracking-links
POST/events/:id/tracking-links
PATCH/tracking-links/:id
DELETE/tracking-links/:id
GET/events/:id/staff-links
POST/events/:id/staff-links
PATCH/staff-links/:id
DELETE/staff-links/:id
GET/events/:id/polls
POST/events/:id/polls
PATCH/polls/:id
DELETE/polls/:id
GET/events/:id/comments
POST/events/:id/comments
PATCH/comments/:id
DELETE/comments/:id
GET/events/:id/blasts
POST/events/:id/blasts
GET/blasts/:id
POST/blasts/:id/send
GET/newsletters
POST/newsletters
GET/people
POST/people
GET/people/:id
PATCH/people/:id
POST/people/:id/notes
DELETE/people/:id/notes/:noteId
POST/people/bulk
GET/people/duplicates
POST/people/:id/merge
GET/segments
POST/segments
GET/segments/:id
PATCH/segments/:id
DELETE/segments/:id
GET/campaigns
POST/campaigns
POST/campaigns/preview
POST/campaigns/test
POST/campaigns/:id/send
GET/deals
POST/deals
GET/deals/:id
PATCH/deals/:id
DELETE/deals/:id
GET/membership-tiers
POST/membership-tiers
PATCH/membership-tiers/:id
DELETE/membership-tiers/:id
GET/members
POST/members/:id/approve
POST/members/:id/cancel
GET/subscribers
POST/subscribers
POST/subscribers/import
GET/subscribers/:id
PATCH/subscribers/:id
DELETE/subscribers/:id
GET/do-not-invite
POST/do-not-invite
DELETE/do-not-invite/:id
GET/team
GET/webhooks
POST/webhooks
GET/webhooks/:id
PATCH/webhooks/:id
DELETE/webhooks/:id
POST/webhooks/:id/test
GET/webhooks/:id/deliveries
POST/webhook-deliveries/:id/redeliver
GET/vendors
GET/events/:id/vendors
GET/venues

Key introspection

Find out which calendar and account a key acts as, and its scope.

GET/api/v1/me

Retrieve the current key

Returns { data: Me }.
curl "https://valore.app/api/v1/me" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "key": {
      "id": "key_1",
      "name": "Zapier",
      "prefix": "vlr_a1b2c3d4",
      "scope": "read_write"
    },
    "calendar": {
      "id": "cal_9x1kq2",
      "slug": "sf-ai-builders",
      "name": "SF AI Builders"
    },
    "user": {
      "id": "usr_1",
      "name": "Jordan Reyes",
      "email": "jordan@example.com"
    },
    "rate_limit": {
      "requests_per_minute": 300
    }
  }
}

Calendar

The calendar (organization) this key belongs to. Every other resource is scoped to it.

GET/api/v1/calendar

Retrieve the calendar

Returns { data: Calendar }.
curl "https://valore.app/api/v1/calendar" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "cal_9x1kq2",
    "slug": "sf-ai-builders",
    "name": "SF AI Builders",
    "description": "Monthly demo nights for people shipping AI products.",
    "url": "https://valore.app/sf-ai-builders",
    "avatar_url": "https://…/avatar.jpg",
    "cover_url": null,
    "tint_color": "#18181b",
    "timezone": "America/Los_Angeles",
    "city": "San Francisco",
    "website_url": "https://sfaibuilders.com",
    "is_personal": false,
    "is_verified": true,
    "event_count": 42,
    "subscriber_count": 1830,
    "created_at": "2026-01-12T18:04:00.000Z"
  }
}
PATCH/api/v1/calendar

Update the calendar

Body parameters
name
string
2–80 characters.
description
string
slug
string
Public URL slug.
timezone
string
IANA zone.
city
string
website_url
string
avatar_url
string
cover_url
string
tint_color
string
Hex, e.g. #18181b.
instagram
string
Handle.
x_handle
string
linkedin
string
Returns { data: Calendar }.
curl -X PATCH "https://valore.app/api/v1/calendar" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "description": "Monthly demo nights for people shipping AI products.",
  "city": "San Francisco"
}'
Response · 200
{
  "data": {
    "id": "cal_9x1kq2",
    "slug": "sf-ai-builders",
    "name": "SF AI Builders",
    "description": "Monthly demo nights for people shipping AI products.",
    "url": "https://valore.app/sf-ai-builders",
    "avatar_url": "https://…/avatar.jpg",
    "cover_url": null,
    "tint_color": "#18181b",
    "timezone": "America/Los_Angeles",
    "city": "San Francisco",
    "website_url": "https://sfaibuilders.com",
    "is_personal": false,
    "is_verified": true,
    "event_count": 42,
    "subscriber_count": 1830,
    "created_at": "2026-01-12T18:04:00.000Z"
  }
}

Brand themes

The calendar's saved event page designs (colors, fonts, background, corners, logo). Create and edit them on the calendar's Branding page; apply one to an event with `theme.brand`.

GET/api/v1/brand-themes

List brand themes

  • is_default marks the theme new events get automatically.
  • Custom fonts are .woff2/.woff/.ttf/.otf files; heading and body are the built-in fallbacks.
Returns { data: BrandTheme[] }.
curl "https://valore.app/api/v1/brand-themes" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "bt_acme",
      "name": "Acme 2026",
      "is_default": true,
      "event_count": 14,
      "colors": {
        "background": "#0b1f3a",
        "surface": "#10294b",
        "text": "#f1f5f9",
        "accent": "#38bdf8"
      },
      "background": {
        "style": "gradient",
        "gradient_to": "#12335f",
        "image_url": null,
        "image_fit": "cover",
        "overlay": 40
      },
      "fonts": {
        "heading": "modern",
        "body": "sans",
        "heading_custom": {
          "name": "Acme Display",
          "url": "https://…/acme-display.woff2"
        },
        "body_custom": null
      },
      "corners": "soft",
      "logo_url": "https://…/acme-logo.png"
    }
  ]
}

Events

Create, update, publish, duplicate, cancel (optionally refunding paid guests) and delete events, and read their analytics.

GET/api/v1/events

List events

  • Sorted by start time, ascending. Includes ticket types.
Query parameters
status
string
draftpublishedcanceled
from
datetime
Events starting at or after this time.
to
datetime
Events starting at or before this time.
upcoming
boolean
true: only events that haven't ended yet.
limit
integerdefault 25
Page size, 1–100.
cursor
string
The next_cursor from the previous page.
Returns a page of Event objects as { data, next_cursor }.
curl "https://valore.app/api/v1/events?status=draft&from=2026-10-01T00:00:00Z" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "evt_7f3ab1",
      "slug": "demo-night-november",
      "url": "https://valore.app/demo-night-november",
      "calendar_id": "cal_9x1kq2",
      "title": "Demo Night · November",
      "description": "Six teams, five minutes each. Drinks after.",
      "cover_url": "https://…/cover.jpg",
      "status": "published",
      "visibility": "public",
      "starts_at": "2026-11-05T02:00:00.000Z",
      "ends_at": "2026-11-05T05:00:00.000Z",
      "timezone": "America/Los_Angeles",
      "location": {
        "type": "in_person",
        "name": "The Foundry",
        "address": "500 Howard St, San Francisco, CA",
        "city": "San Francisco",
        "region": "CA",
        "country": "US",
        "latitude": 37.788,
        "longitude": -122.396,
        "virtual_url": null
      },
      "category": "tech",
      "tags": [
        "ai",
        "demos"
      ],
      "capacity": 120,
      "require_approval": true,
      "waitlist_enabled": true,
      "registration_open": true,
      "registration_closes_at": null,
      "intros_enabled": true,
      "intros_setting": "automatic",
      "currency": "usd",
      "brand_theme_id": "bt_acme",
      "ticket_types": [
        {
          "id": "tt_01",
          "event_id": "evt_7f3ab1",
          "name": "General Admission",
          "description": null,
          "price_cents": 0,
          "quantity": null,
          "max_per_order": 1,
          "sales_start_at": null,
          "sales_end_at": null,
          "require_approval": false,
          "hidden": false,
          "sort_order": 0,
          "pricing_mode": "fixed",
          "created_at": "2026-10-01T17:00:00.000Z"
        }
      ],
      "published_at": "2026-10-01T17:00:00.000Z",
      "canceled_at": null,
      "created_at": "2026-10-01T16:58:00.000Z",
      "updated_at": "2026-10-02T09:12:00.000Z"
    }
  ],
  "next_cursor": "evt_7f3ab1"
}
POST/api/v1/events

Create an event

  • The key's owner becomes the first host.
  • A default ticket type is created: free, or priced at price_cents.
Body parameters
title
stringrequired
Up to 200 characters.
starts_at
datetimerequired
ISO 8601 with offset, or a wall-clock time (2026-11-05T18:00) interpreted in timezone.
ends_at
datetime
Defaults to two hours after starts_at.
timezone
string
IANA zone, e.g. America/Los_Angeles. Defaults to the calendar's.
description
string
Markdown.
cover_url
string
HTTPS image URL.
status
string
Defaults to published on create.
draftpublished
visibility
string
Private events require an invitation to register.
publicunlistedprivate
location_type
string
Or send a nested location object as returned by the API.
in_personvirtualhybridtbd
location_name
string
Venue name.
address
string
Street address.
city
string
virtual_url
string
Meeting link, revealed to confirmed guests.
capacity
integer
Omit for unlimited.
require_approval
boolean
Registrations land in pending_approval.
waitlist_enabled
boolean
registration_open
boolean
registration_closes_at
datetime
intros_enabled
boolean
Night-before intros: guests say who they want to meet, and the evening before Valore emails each the host plus their top 3 people. null (the default) is automatic: on unless the guest list is hidden or anonymized.
price_cents
integer
Create only: price of the default ticket (0 = free).
currency
stringdefault usd
ISO 4217, lowercase.
category
string
tags
string[]
slug
string
Custom URL slug (3–64 chars, lowercase).
theme
object
Page design. { "brand": "bt_…" } applies a brand theme from GET /brand-themes; { "brand": null } switches to the event's own theme. New events without theme.brand get the calendar's default brand theme, if it has one.
Returns { data: Event } with status 201.
curl -X POST "https://valore.app/api/v1/events" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Founders Breakfast",
  "starts_at": "2026-11-05T09:00",
  "ends_at": "2026-11-05T11:00",
  "timezone": "America/Los_Angeles",
  "location_type": "in_person",
  "location_name": "Sightglass Coffee",
  "address": "270 7th St, San Francisco, CA",
  "capacity": 40,
  "require_approval": true
}'
Response · 201
{
  "data": {
    "id": "evt_7f3ab1",
    "slug": "demo-night-november",
    "url": "https://valore.app/demo-night-november",
    "calendar_id": "cal_9x1kq2",
    "title": "Demo Night · November",
    "description": "Six teams, five minutes each. Drinks after.",
    "cover_url": "https://…/cover.jpg",
    "status": "published",
    "visibility": "public",
    "starts_at": "2026-11-05T02:00:00.000Z",
    "ends_at": "2026-11-05T05:00:00.000Z",
    "timezone": "America/Los_Angeles",
    "location": {
      "type": "in_person",
      "name": "The Foundry",
      "address": "500 Howard St, San Francisco, CA",
      "city": "San Francisco",
      "region": "CA",
      "country": "US",
      "latitude": 37.788,
      "longitude": -122.396,
      "virtual_url": null
    },
    "category": "tech",
    "tags": [
      "ai",
      "demos"
    ],
    "capacity": 120,
    "require_approval": true,
    "waitlist_enabled": true,
    "registration_open": true,
    "registration_closes_at": null,
    "intros_enabled": true,
    "intros_setting": "automatic",
    "currency": "usd",
    "brand_theme_id": "bt_acme",
    "ticket_types": [
      {
        "id": "tt_01",
        "event_id": "evt_7f3ab1",
        "name": "General Admission",
        "description": null,
        "price_cents": 0,
        "quantity": null,
        "max_per_order": 1,
        "sales_start_at": null,
        "sales_end_at": null,
        "require_approval": false,
        "hidden": false,
        "sort_order": 0,
        "pricing_mode": "fixed",
        "created_at": "2026-10-01T17:00:00.000Z"
      }
    ],
    "published_at": "2026-10-01T17:00:00.000Z",
    "canceled_at": null,
    "created_at": "2026-10-01T16:58:00.000Z",
    "updated_at": "2026-10-02T09:12:00.000Z"
  }
}
GET/api/v1/events/:id

Retrieve an event

  • Includes live guest stats and night-before intros counts.
Returns { data: EventWithStats }.
curl "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "evt_7f3ab1",
    "slug": "demo-night-november",
    "url": "https://valore.app/demo-night-november",
    "calendar_id": "cal_9x1kq2",
    "title": "Demo Night · November",
    "description": "Six teams, five minutes each. Drinks after.",
    "cover_url": "https://…/cover.jpg",
    "status": "published",
    "visibility": "public",
    "starts_at": "2026-11-05T02:00:00.000Z",
    "ends_at": "2026-11-05T05:00:00.000Z",
    "timezone": "America/Los_Angeles",
    "location": {
      "type": "in_person",
      "name": "The Foundry",
      "address": "500 Howard St, San Francisco, CA",
      "city": "San Francisco",
      "region": "CA",
      "country": "US",
      "latitude": 37.788,
      "longitude": -122.396,
      "virtual_url": null
    },
    "category": "tech",
    "tags": [
      "ai",
      "demos"
    ],
    "capacity": 120,
    "require_approval": true,
    "waitlist_enabled": true,
    "registration_open": true,
    "registration_closes_at": null,
    "intros_enabled": true,
    "intros_setting": "automatic",
    "currency": "usd",
    "brand_theme_id": "bt_acme",
    "ticket_types": [
      {
        "id": "tt_01",
        "event_id": "evt_7f3ab1",
        "name": "General Admission",
        "description": null,
        "price_cents": 0,
        "quantity": null,
        "max_per_order": 1,
        "sales_start_at": null,
        "sales_end_at": null,
        "require_approval": false,
        "hidden": false,
        "sort_order": 0,
        "pricing_mode": "fixed",
        "created_at": "2026-10-01T17:00:00.000Z"
      }
    ],
    "published_at": "2026-10-01T17:00:00.000Z",
    "canceled_at": null,
    "created_at": "2026-10-01T16:58:00.000Z",
    "updated_at": "2026-10-02T09:12:00.000Z",
    "stats": {
      "going": 84,
      "pending_approval": 6,
      "waitlist": 0,
      "invited": 12,
      "declined": 2,
      "not_going": 3,
      "checked_in": 0,
      "capacity": 120,
      "spots_left": 36,
      "revenue_cents": 0,
      "page_views": 1412
    },
    "intros": {
      "enabled": true,
      "setting": "automatic",
      "sends_at": "2026-11-05T02:00:00.000Z",
      "answered": 41,
      "opted_in": 57,
      "sent": 0
    }
  }
}
PATCH/api/v1/events/:id

Update an event

Body parameters
title
string
Up to 200 characters.
starts_at
datetime
ISO 8601 with offset, or a wall-clock time (2026-11-05T18:00) interpreted in timezone.
ends_at
datetime
Defaults to two hours after starts_at.
timezone
string
IANA zone, e.g. America/Los_Angeles. Defaults to the calendar's.
description
string
Markdown.
cover_url
string
HTTPS image URL.
status
string
canceled cancels the event and emails confirmed guests.
draftpublishedcanceled
visibility
string
Private events require an invitation to register.
publicunlistedprivate
location_type
string
Or send a nested location object as returned by the API.
in_personvirtualhybridtbd
location_name
string
Venue name.
address
string
Street address.
city
string
virtual_url
string
Meeting link, revealed to confirmed guests.
capacity
integer
Omit for unlimited.
require_approval
boolean
Registrations land in pending_approval.
waitlist_enabled
boolean
registration_open
boolean
registration_closes_at
datetime
intros_enabled
boolean
Night-before intros: guests say who they want to meet, and the evening before Valore emails each the host plus their top 3 people. null (the default) is automatic: on unless the guest list is hidden or anonymized.
currency
stringdefault usd
ISO 4217, lowercase.
category
string
tags
string[]
slug
string
Custom URL slug (3–64 chars, lowercase).
theme
object
Page design. { "brand": "bt_…" } applies a brand theme from GET /brand-themes; { "brand": null } switches to the event's own theme. New events without theme.brand get the calendar's default brand theme, if it has one.
cancellation_note
string
Included in the cancellation email.
refund_paid_guests
boolean
With status: "canceled": refund every paid guest in full. Refunds that fail are listed for the hosts in Valore.
notify_guests
booleandefault true
Email confirmed guests about time/location changes.
Returns { data: EventWithStats }.
curl -X PATCH "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Founders Breakfast (Vol. 2)",
  "capacity": 60
}'
Response · 200
{
  "data": {
    "id": "evt_7f3ab1",
    "slug": "demo-night-november",
    "url": "https://valore.app/demo-night-november",
    "calendar_id": "cal_9x1kq2",
    "title": "Demo Night · November",
    "description": "Six teams, five minutes each. Drinks after.",
    "cover_url": "https://…/cover.jpg",
    "status": "published",
    "visibility": "public",
    "starts_at": "2026-11-05T02:00:00.000Z",
    "ends_at": "2026-11-05T05:00:00.000Z",
    "timezone": "America/Los_Angeles",
    "location": {
      "type": "in_person",
      "name": "The Foundry",
      "address": "500 Howard St, San Francisco, CA",
      "city": "San Francisco",
      "region": "CA",
      "country": "US",
      "latitude": 37.788,
      "longitude": -122.396,
      "virtual_url": null
    },
    "category": "tech",
    "tags": [
      "ai",
      "demos"
    ],
    "capacity": 120,
    "require_approval": true,
    "waitlist_enabled": true,
    "registration_open": true,
    "registration_closes_at": null,
    "intros_enabled": true,
    "intros_setting": "automatic",
    "currency": "usd",
    "brand_theme_id": "bt_acme",
    "ticket_types": [
      {
        "id": "tt_01",
        "event_id": "evt_7f3ab1",
        "name": "General Admission",
        "description": null,
        "price_cents": 0,
        "quantity": null,
        "max_per_order": 1,
        "sales_start_at": null,
        "sales_end_at": null,
        "require_approval": false,
        "hidden": false,
        "sort_order": 0,
        "pricing_mode": "fixed",
        "created_at": "2026-10-01T17:00:00.000Z"
      }
    ],
    "published_at": "2026-10-01T17:00:00.000Z",
    "canceled_at": null,
    "created_at": "2026-10-01T16:58:00.000Z",
    "updated_at": "2026-10-02T09:12:00.000Z",
    "stats": {
      "going": 84,
      "pending_approval": 6,
      "waitlist": 0,
      "invited": 12,
      "declined": 2,
      "not_going": 3,
      "checked_in": 0,
      "capacity": 120,
      "spots_left": 36,
      "revenue_cents": 0,
      "page_views": 1412
    },
    "intros": {
      "enabled": true,
      "setting": "automatic",
      "sends_at": "2026-11-05T02:00:00.000Z",
      "answered": 41,
      "opted_in": 57,
      "sent": 0
    }
  }
}
POST/api/v1/events/:id/publish

Publish a draft

Returns { data: Event }.
curl -X POST "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/publish" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "evt_7f3ab1",
    "slug": "demo-night-november",
    "url": "https://valore.app/demo-night-november",
    "calendar_id": "cal_9x1kq2",
    "title": "Demo Night · November",
    "description": "Six teams, five minutes each. Drinks after.",
    "cover_url": "https://…/cover.jpg",
    "status": "published",
    "visibility": "public",
    "starts_at": "2026-11-05T02:00:00.000Z",
    "ends_at": "2026-11-05T05:00:00.000Z",
    "timezone": "America/Los_Angeles",
    "location": {
      "type": "in_person",
      "name": "The Foundry",
      "address": "500 Howard St, San Francisco, CA",
      "city": "San Francisco",
      "region": "CA",
      "country": "US",
      "latitude": 37.788,
      "longitude": -122.396,
      "virtual_url": null
    },
    "category": "tech",
    "tags": [
      "ai",
      "demos"
    ],
    "capacity": 120,
    "require_approval": true,
    "waitlist_enabled": true,
    "registration_open": true,
    "registration_closes_at": null,
    "intros_enabled": true,
    "intros_setting": "automatic",
    "currency": "usd",
    "brand_theme_id": "bt_acme",
    "ticket_types": [
      {
        "id": "tt_01",
        "event_id": "evt_7f3ab1",
        "name": "General Admission",
        "description": null,
        "price_cents": 0,
        "quantity": null,
        "max_per_order": 1,
        "sales_start_at": null,
        "sales_end_at": null,
        "require_approval": false,
        "hidden": false,
        "sort_order": 0,
        "pricing_mode": "fixed",
        "created_at": "2026-10-01T17:00:00.000Z"
      }
    ],
    "published_at": "2026-10-01T17:00:00.000Z",
    "canceled_at": null,
    "created_at": "2026-10-01T16:58:00.000Z",
    "updated_at": "2026-10-02T09:12:00.000Z"
  }
}
POST/api/v1/events/:id/duplicate

Duplicate an event

  • Copies settings, ticket types, questions and hosts as a new draft. Guests are not copied.
Body parameters
starts_at
datetime
New start (same duration). Defaults to one week later.
title
string
Defaults to the original title.
Returns { data: Event } with status 201.
curl -X POST "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/duplicate" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "starts_at": "2026-12-03T18:00",
  "title": "Demo Night · December"
}'
Response · 201
{
  "data": {
    "id": "evt_7f3ab1",
    "slug": "demo-night-november",
    "url": "https://valore.app/demo-night-november",
    "calendar_id": "cal_9x1kq2",
    "title": "Demo Night · November",
    "description": "Six teams, five minutes each. Drinks after.",
    "cover_url": "https://…/cover.jpg",
    "status": "draft",
    "visibility": "public",
    "starts_at": "2026-11-05T02:00:00.000Z",
    "ends_at": "2026-11-05T05:00:00.000Z",
    "timezone": "America/Los_Angeles",
    "location": {
      "type": "in_person",
      "name": "The Foundry",
      "address": "500 Howard St, San Francisco, CA",
      "city": "San Francisco",
      "region": "CA",
      "country": "US",
      "latitude": 37.788,
      "longitude": -122.396,
      "virtual_url": null
    },
    "category": "tech",
    "tags": [
      "ai",
      "demos"
    ],
    "capacity": 120,
    "require_approval": true,
    "waitlist_enabled": true,
    "registration_open": true,
    "registration_closes_at": null,
    "intros_enabled": true,
    "intros_setting": "automatic",
    "currency": "usd",
    "brand_theme_id": "bt_acme",
    "ticket_types": [
      {
        "id": "tt_01",
        "event_id": "evt_7f3ab1",
        "name": "General Admission",
        "description": null,
        "price_cents": 0,
        "quantity": null,
        "max_per_order": 1,
        "sales_start_at": null,
        "sales_end_at": null,
        "require_approval": false,
        "hidden": false,
        "sort_order": 0,
        "pricing_mode": "fixed",
        "created_at": "2026-10-01T17:00:00.000Z"
      }
    ],
    "published_at": "2026-10-01T17:00:00.000Z",
    "canceled_at": null,
    "created_at": "2026-10-01T16:58:00.000Z",
    "updated_at": "2026-10-02T09:12:00.000Z"
  }
}
DELETE/api/v1/events/:id

Delete an event

  • Refused (409) when anyone has paid. Cancel with refunds instead: PATCH /events/:id with status: "canceled" and refund_paid_guests: true.
Returns { data }.
curl -X DELETE "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "evt_7f3ab1",
    "deleted": true
  }
}
GET/api/v1/events/:id/insights

Event analytics

Guest stats, page views and conversion, registrations by day, top traffic sources, guest sources, feedback ratings and email performance.

Returns { data }.
curl "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/insights" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "event": {
      "id": "evt_7f3ab1",
      "title": "Demo Night · November",
      "url": "https://valore.app/demo-night-november",
      "starts_at": "2026-11-05T02:00:00.000Z",
      "status": "published"
    },
    "stats": {
      "going": 96,
      "pending_approval": 4,
      "waitlist": 12,
      "invited": 30,
      "declined": 3,
      "not_going": 5,
      "checked_in": 71,
      "capacity": 120,
      "spots_left": 24,
      "revenue_cents": 0,
      "currency": "usd",
      "page_views": 1840,
      "view_to_registration_pct": 6.2,
      "check_in_rate_pct": 74
    },
    "registrations_by_day": [
      {
        "day": "2026-10-28",
        "count": 14
      }
    ],
    "top_traffic_sources": [
      {
        "source": "newsletter",
        "views": 620
      }
    ],
    "guest_sources": [
      {
        "source": "newsletter",
        "guests": 31
      }
    ],
    "feedback": {
      "count": 22,
      "avg_rating": 4.6,
      "recent_comments": [
        "Great demos, tight timing."
      ]
    },
    "emails": [
      {
        "kind": "reminder",
        "sent": 112,
        "opened": 81,
        "open_rate_pct": 72.3,
        "click_rate_pct": 18.8
      }
    ]
  }
}

Guests

Registrations for an event: approve, decline, waitlist, check in, add or remove people.

GET/api/v1/events/:id/guests

List an event's guests

Query parameters
status
string
goingpending_approvalwaitlistinviteddeclinednot_going
checked_in
boolean
true: only checked-in guests; false: only guests not checked in.
search
string
Name or email contains.
limit
integerdefault 25
Page size, 1–100.
cursor
string
The next_cursor from the previous page.
Returns a page of Guest objects as { data, next_cursor }.
curl "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/guests?status=going&checked_in=demo" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "gst_2c9d10",
      "event_id": "evt_7f3ab1",
      "name": "Ada Lovelace",
      "email": "ada@example.com",
      "phone": null,
      "status": "going",
      "quantity": 1,
      "ticket_type_id": "tt_01",
      "answers": {
        "company": "Analytical Engines Ltd"
      },
      "amount_cents": 0,
      "currency": "usd",
      "payment_status": "none",
      "checked_in_at": null,
      "registered_at": "2026-10-03T21:14:09.000Z",
      "source": "page",
      "plus_ones": 0,
      "plus_one_names": [],
      "fee_cents": 0,
      "tax_cents": 0,
      "refunded_cents": 0
    }
  ],
  "next_cursor": "gst_2c9d10"
}
GET/api/v1/guests

Search guests across the calendar

Query parameters
email
email
Exact match.
q
string
Name or email contains.
status
string
goingpending_approvalwaitlistinviteddeclinednot_going
event_id
string
limit
integerdefault 25
Page size, 1–100.
cursor
string
The next_cursor from the previous page.
Returns a page of Guest objects as { data, next_cursor }.
curl "https://valore.app/api/v1/guests?email=ada@example.com&q=demo" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "gst_2c9d10",
      "event_id": "evt_7f3ab1",
      "name": "Ada Lovelace",
      "email": "ada@example.com",
      "phone": null,
      "status": "going",
      "quantity": 1,
      "ticket_type_id": "tt_01",
      "answers": {
        "company": "Analytical Engines Ltd"
      },
      "amount_cents": 0,
      "currency": "usd",
      "payment_status": "none",
      "checked_in_at": null,
      "registered_at": "2026-10-03T21:14:09.000Z",
      "source": "page",
      "plus_ones": 0,
      "plus_one_names": [],
      "fee_cents": 0,
      "tax_cents": 0,
      "refunded_cents": 0
    }
  ],
  "next_cursor": "gst_2c9d10"
}
GET/api/v1/attendees

Export attendees across events

Every attendee of the calendar's events in one list, each with the event they attended: for syncing a CRM or building a mailing list. Pick events with `event_ids`, or a date range with `from`/`to`; omit both for all events.

  • By default only registered guests are returned (going, maybe, waitlist, pending approval). Pass include=all to add invited and declined people.
  • event_ids must all belong to the key's calendar; an unknown id is a 404.
  • Results are ordered by event start, then guest, so paging is stable while you export.
Query parameters
event_ids
string
Comma-separated event ids. Omit for every event on the calendar.
from
datetime
Only events starting at or after this time (ISO 8601).
to
datetime
Only events starting before this time (ISO 8601).
include
stringdefault active
active (default): registered guests. all: also invited and declined.
activeall
limit
integerdefault 25
Page size, 1–100.
cursor
string
The next_cursor from the previous page.
Returns a page of Guest[] (each with an `event` object) objects as { data, next_cursor }.
curl "https://valore.app/api/v1/attendees?event_ids=demo&from=2026-10-01T00:00:00Z" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "gst_2c9d10",
      "event_id": "evt_7f3ab1",
      "name": "Ada Lovelace",
      "email": "ada@example.com",
      "phone": null,
      "status": "going",
      "quantity": 1,
      "ticket_type_id": "tt_01",
      "answers": {
        "company": "Analytical Engines Ltd"
      },
      "amount_cents": 0,
      "currency": "usd",
      "payment_status": "none",
      "checked_in_at": null,
      "registered_at": "2026-10-03T21:14:09.000Z",
      "source": "page",
      "plus_ones": 0,
      "plus_one_names": [],
      "fee_cents": 0,
      "tax_cents": 0,
      "refunded_cents": 0,
      "event": {
        "id": "evt_7f3ab1",
        "title": "Founders Breakfast",
        "slug": "founders-breakfast",
        "starts_at": "2026-11-05T16:00:00.000Z",
        "timezone": "America/Los_Angeles"
      }
    }
  ],
  "next_cursor": "gst_2c9d10"
}
POST/api/v1/events/:id/guests

Add guests directly

  • Guests are added as going and skip approval and capacity checks. Existing guests are returned unchanged.
Body parameters
guests
object[]required
Up to 500 { email, name? } objects.
notify
booleandefault true
Send the confirmation email.
Returns { data: Guest[] } with status 201.
curl -X POST "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/guests" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "guests": [
    {
      "email": "ada@example.com",
      "name": "Ada Lovelace"
    }
  ],
  "notify": true
}'
Response · 201
{
  "data": [
    {
      "id": "gst_2c9d10",
      "event_id": "evt_7f3ab1",
      "name": "Ada Lovelace",
      "email": "ada@example.com",
      "phone": null,
      "status": "going",
      "quantity": 1,
      "ticket_type_id": "tt_01",
      "answers": {
        "company": "Analytical Engines Ltd"
      },
      "amount_cents": 0,
      "currency": "usd",
      "payment_status": "none",
      "checked_in_at": null,
      "registered_at": "2026-10-03T21:14:09.000Z",
      "source": "page",
      "plus_ones": 0,
      "plus_one_names": [],
      "fee_cents": 0,
      "tax_cents": 0,
      "refunded_cents": 0
    }
  ]
}
GET/api/v1/guests/:id

Retrieve a guest

Returns { data: Guest }.
curl "https://valore.app/api/v1/guests/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "gst_2c9d10",
    "event_id": "evt_7f3ab1",
    "name": "Ada Lovelace",
    "email": "ada@example.com",
    "phone": null,
    "status": "going",
    "quantity": 1,
    "ticket_type_id": "tt_01",
    "answers": {
      "company": "Analytical Engines Ltd"
    },
    "amount_cents": 0,
    "currency": "usd",
    "payment_status": "none",
    "checked_in_at": null,
    "registered_at": "2026-10-03T21:14:09.000Z",
    "source": "page",
    "plus_ones": 0,
    "plus_one_names": [],
    "fee_cents": 0,
    "tax_cents": 0,
    "refunded_cents": 0
  }
}
PATCH/api/v1/guests/:id

Update a guest

  • Approving a guest who still owes payment keeps them pending with payment_status: "pending" until they pay.
Body parameters
status
string
Approve (going), decline, waitlist…
goingpending_approvalwaitlistinviteddeclinednot_going
notify
booleandefault true
Email the guest about the status change.
note
string
Message included in the email.
refund
boolean
Refund a paid guest being declined or removed.
name
string
phone
string
host_note
string
Private note visible to hosts only.
Returns { data: Guest }.
curl -X PATCH "https://valore.app/api/v1/guests/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "going"
}'
Response · 200
{
  "data": {
    "id": "gst_2c9d10",
    "event_id": "evt_7f3ab1",
    "name": "Ada Lovelace",
    "email": "ada@example.com",
    "phone": null,
    "status": "going",
    "quantity": 1,
    "ticket_type_id": "tt_01",
    "answers": {
      "company": "Analytical Engines Ltd"
    },
    "amount_cents": 0,
    "currency": "usd",
    "payment_status": "none",
    "checked_in_at": null,
    "registered_at": "2026-10-03T21:14:09.000Z",
    "source": "page",
    "plus_ones": 0,
    "plus_one_names": [],
    "fee_cents": 0,
    "tax_cents": 0,
    "refunded_cents": 0
  }
}
POST/api/v1/guests/:id/check-in

Check a guest in

  • Only going guests can be checked in. The response adds already_checked_in.
Query parameters
undo
boolean
Reverse a check-in.
Returns { data: Guest }.
curl -X POST "https://valore.app/api/v1/guests/EVENT_OR_RESOURCE_ID/check-in" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "gst_2c9d10",
    "event_id": "evt_7f3ab1",
    "name": "Ada Lovelace",
    "email": "ada@example.com",
    "phone": null,
    "status": "going",
    "quantity": 1,
    "ticket_type_id": "tt_01",
    "answers": {
      "company": "Analytical Engines Ltd"
    },
    "amount_cents": 0,
    "currency": "usd",
    "payment_status": "none",
    "checked_in_at": "2026-11-05T02:04:00.000Z",
    "registered_at": "2026-10-03T21:14:09.000Z",
    "source": "page",
    "plus_ones": 0,
    "plus_one_names": [],
    "fee_cents": 0,
    "tax_cents": 0,
    "refunded_cents": 0,
    "already_checked_in": false
  }
}
DELETE/api/v1/guests/:id

Remove a guest

  • Marks them not_going without emailing them.
Query parameters
refund
boolean
Also refund a paid ticket.
Returns { data }.
curl -X DELETE "https://valore.app/api/v1/guests/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "gst_2c9d10",
    "removed": true
  }
}

Invitations

Email invitations to an event, and whether they were opened or accepted.

GET/api/v1/events/:id/invites

List invitations

Query parameters
limit
integerdefault 25
Page size, 1–100.
cursor
string
The next_cursor from the previous page.
Returns a page of Invite objects as { data, next_cursor }.
curl "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/invites" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "inv_5",
      "event_id": "evt_7f3ab1",
      "email": "alan@example.com",
      "name": "Alan",
      "status": "opened",
      "sent_at": "2026-10-02T10:00:00.000Z",
      "opened_at": "2026-10-02T10:42:00.000Z",
      "responded_at": null
    }
  ],
  "next_cursor": "inv_5"
}
POST/api/v1/events/:id/invites

Send invitations

  • Invites come from the key's owner. People already going are skipped. A 10-minute cooldown applies per address.
  • With send_text: true, anyone whose phone is given is also texted the same RSVP link — when SMS is configured for the workspace and that number hasn't replied STOP. Everyone still gets the email, and texts_skipped counts the numbers that were opted out or unreachable. excluded counts people left out because they are on the calendar's do-not-invite list, opted out of this host's invites, are blocked, or have an address that hard-bounced or marked Valore mail as spam.
Body parameters
emails
string[]required
Up to 500 emails or { email, name, phone } objects.
message
string
Personal note in the email (2,000 chars).
send_text
boolean
Also text the RSVP link to people with a phone number. Ignored when SMS isn't configured.
Returns { data } with status 201.
curl -X POST "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/invites" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "emails": [
    "grace@example.com",
    {
      "email": "alan@example.com",
      "name": "Alan",
      "phone": "+14155550123"
    }
  ],
  "message": "Would love to see you there!",
  "send_text": true
}'
Response · 201
{
  "data": {
    "sent": 2,
    "skipped": 0,
    "excluded": 0,
    "texted": 1,
    "texts_skipped": 0
  }
}
POST/api/v1/events/:id/invites/check

Check a list before inviting

Flags addresses that shouldn't be invited: on the do-not-invite list, opted out, complained, bounced, unsubscribed, invalid, a misspelled domain (with `suggestion`), or a domain with no mail server. Addresses with no issue are left out. Sends nothing.

Body parameters
emails
string[]required
Returns { data }.
curl -X POST "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/invites/check" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "emails": [
    "ada@gmial.com",
    "linus@example.com"
  ]
}'
Response · 200
{
  "data": [
    {
      "email": "ada@gmial.com",
      "kind": "typo",
      "suggestion": "ada@gmail.com"
    }
  ],
  "checked": 2
}

Hosts & staff

Who runs an event: hosts (shown on the page), managers (hidden) and check-in staff.

GET/api/v1/events/:id/hosts

List hosts

Returns { data: Host[] }.
curl "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/hosts" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "hst_1",
      "event_id": "evt_7f3ab1",
      "email": "grace@example.com",
      "name": "Grace Hopper",
      "role": "host",
      "status": "accepted",
      "user_id": "usr_88",
      "avatar_url": null,
      "created_at": "2026-10-01T17:00:00.000Z"
    }
  ]
}
POST/api/v1/events/:id/hosts

Add a host, manager or checker

  • They're emailed. If they don't have an account yet, access activates when they sign up with that email.
Body parameters
email
emailrequired
name
string
role
stringdefault host
Checkers can only scan tickets.
hostmanagerchecker
Returns { data: Host } with status 201.
curl -X POST "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/hosts" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "grace@example.com",
  "name": "Grace Hopper",
  "role": "host"
}'
Response · 201
{
  "data": {
    "id": "hst_1",
    "event_id": "evt_7f3ab1",
    "email": "grace@example.com",
    "name": "Grace Hopper",
    "role": "host",
    "status": "accepted",
    "user_id": "usr_88",
    "avatar_url": null,
    "created_at": "2026-10-01T17:00:00.000Z"
  }
}
DELETE/api/v1/events/:id/hosts/:hostId

Remove a host

  • An event always keeps at least one host.
Returns { data }.
curl -X DELETE "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/hosts/HOST_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "hst_1",
    "removed": true
  }
}

Ticket types

Free and paid tickets. Prices are integer cents in the event's currency.

GET/api/v1/events/:id/ticket-types

List ticket types

Returns { data: TicketType[] }.
curl "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/ticket-types" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "tt_02",
      "event_id": "evt_7f3ab1",
      "name": "Supporter",
      "description": "Covers a student's ticket.",
      "price_cents": 2500,
      "quantity": 50,
      "max_per_order": 4,
      "sales_start_at": null,
      "sales_end_at": "2026-11-04T23:59:00.000Z",
      "require_approval": false,
      "hidden": false,
      "sort_order": 1,
      "pricing_mode": "fixed",
      "created_at": "2026-10-01T17:05:00.000Z"
    }
  ]
}
POST/api/v1/events/:id/ticket-types

Create a ticket type

Body parameters
name
stringrequired
description
string
price_cents
integerdefault 0
0 = free; paid tickets are at least 50.
quantity
integer
Omit for unlimited.
max_per_order
integerdefault 1
1–20.
sales_start_at
datetime
sales_end_at
datetime
require_approval
boolean
hidden
boolean
Not shown on the event page.
Returns { data: TicketType } with status 201.
curl -X POST "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/ticket-types" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Supporter",
  "price_cents": 2500,
  "quantity": 50,
  "max_per_order": 4
}'
Response · 201
{
  "data": {
    "id": "tt_02",
    "event_id": "evt_7f3ab1",
    "name": "Supporter",
    "description": "Covers a student's ticket.",
    "price_cents": 2500,
    "quantity": 50,
    "max_per_order": 4,
    "sales_start_at": null,
    "sales_end_at": "2026-11-04T23:59:00.000Z",
    "require_approval": false,
    "hidden": false,
    "sort_order": 1,
    "pricing_mode": "fixed",
    "created_at": "2026-10-01T17:05:00.000Z"
  }
}
GET/api/v1/ticket-types/:id

Retrieve a ticket type

Returns { data: TicketType }.
curl "https://valore.app/api/v1/ticket-types/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "tt_02",
    "event_id": "evt_7f3ab1",
    "name": "Supporter",
    "description": "Covers a student's ticket.",
    "price_cents": 2500,
    "quantity": 50,
    "max_per_order": 4,
    "sales_start_at": null,
    "sales_end_at": "2026-11-04T23:59:00.000Z",
    "require_approval": false,
    "hidden": false,
    "sort_order": 1,
    "pricing_mode": "fixed",
    "created_at": "2026-10-01T17:05:00.000Z"
  }
}
PATCH/api/v1/ticket-types/:id

Update a ticket type

Body parameters
name
string
description
string
price_cents
integer
0 = free; paid tickets are at least 50.
quantity
integer
Omit for unlimited.
max_per_order
integer
1–20.
sales_start_at
datetime
sales_end_at
datetime
require_approval
boolean
hidden
boolean
Not shown on the event page.
Returns { data: TicketType }.
curl -X PATCH "https://valore.app/api/v1/ticket-types/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "hidden": true
}'
Response · 200
{
  "data": {
    "id": "tt_02",
    "event_id": "evt_7f3ab1",
    "name": "Supporter",
    "description": "Covers a student's ticket.",
    "price_cents": 2500,
    "quantity": 50,
    "max_per_order": 4,
    "sales_start_at": null,
    "sales_end_at": "2026-11-04T23:59:00.000Z",
    "require_approval": false,
    "hidden": false,
    "sort_order": 1,
    "pricing_mode": "fixed",
    "created_at": "2026-10-01T17:05:00.000Z"
  }
}
DELETE/api/v1/ticket-types/:id

Delete a ticket type

  • Refused while going, pending or waitlisted guests hold it (set hidden: true instead) or if it's the event's last ticket type. Guests in other statuses lose the ticket reference.
Returns { data }.
curl -X DELETE "https://valore.app/api/v1/ticket-types/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "tt_02",
    "deleted": true
  }
}

Coupons

Discount codes for paid tickets.

GET/api/v1/events/:id/coupons

List coupons

Returns { data: Coupon[] }.
curl "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/coupons" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "cpn_3a",
      "event_id": "evt_7f3ab1",
      "code": "FRIENDS20",
      "percent_off": 20,
      "amount_off_cents": null,
      "fixed_price_cents": null,
      "max_uses": 100,
      "used_count": 12,
      "expires_at": null,
      "active": true,
      "created_at": "2026-10-01T17:06:00.000Z"
    }
  ]
}
POST/api/v1/events/:id/coupons

Create a coupon

Body parameters
code
stringrequired
2–40 chars; letters, numbers, dashes, underscores. Stored uppercase.
percent_off
integer
1–100. Set this or amount_off_cents.
amount_off_cents
integer
max_uses
integer
expires_at
datetime
active
booleandefault true
Returns { data: Coupon } with status 201.
curl -X POST "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/coupons" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "code": "FRIENDS20",
  "percent_off": 20,
  "max_uses": 100
}'
Response · 201
{
  "data": {
    "id": "cpn_3a",
    "event_id": "evt_7f3ab1",
    "code": "FRIENDS20",
    "percent_off": 20,
    "amount_off_cents": null,
    "fixed_price_cents": null,
    "max_uses": 100,
    "used_count": 12,
    "expires_at": null,
    "active": true,
    "created_at": "2026-10-01T17:06:00.000Z"
  }
}
GET/api/v1/coupons/:id

Retrieve a coupon

Returns { data: Coupon }.
curl "https://valore.app/api/v1/coupons/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "cpn_3a",
    "event_id": "evt_7f3ab1",
    "code": "FRIENDS20",
    "percent_off": 20,
    "amount_off_cents": null,
    "fixed_price_cents": null,
    "max_uses": 100,
    "used_count": 12,
    "expires_at": null,
    "active": true,
    "created_at": "2026-10-01T17:06:00.000Z"
  }
}
PATCH/api/v1/coupons/:id

Update a coupon

  • Changing code returns 409 if another coupon on the event uses it.
  • A coupon has percent_off or amount_off_cents, never both: to switch, set the other to null in the same request.
Body parameters
code
string
2–40 chars; letters, numbers, dashes, underscores. Stored uppercase.
percent_off
integer
1–100. Set this or amount_off_cents.
amount_off_cents
integer
max_uses
integer
expires_at
datetime
active
boolean
Returns { data: Coupon }.
curl -X PATCH "https://valore.app/api/v1/coupons/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "active": false
}'
Response · 200
{
  "data": {
    "id": "cpn_3a",
    "event_id": "evt_7f3ab1",
    "code": "FRIENDS20",
    "percent_off": 20,
    "amount_off_cents": null,
    "fixed_price_cents": null,
    "max_uses": 100,
    "used_count": 12,
    "expires_at": null,
    "active": false,
    "created_at": "2026-10-01T17:06:00.000Z"
  }
}
DELETE/api/v1/coupons/:id

Delete a coupon

Returns { data }.
curl -X DELETE "https://valore.app/api/v1/coupons/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "cpn_3a",
    "deleted": true
  }
}

Registration questions

Questions guests answer when registering. Answers appear on the guest as `answers`.

GET/api/v1/events/:id/questions

List questions

Returns { data: Question[] }.
curl "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/questions" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "q_1",
      "event_id": "evt_7f3ab1",
      "label": "What are you building?",
      "type": "long_text",
      "options": [],
      "required": true,
      "sort_order": 0,
      "created_at": "2026-10-01T17:07:00.000Z"
    }
  ]
}
POST/api/v1/events/:id/questions

Add a question

Body parameters
label
stringrequired
type
stringdefault text
textlong_textselectmulti_selectcheckboxurlphonecompanysocialterms
options
string[]
For select / multi_select.
required
boolean
Returns { data: Question } with status 201.
curl -X POST "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/questions" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "label": "What are you building?",
  "type": "long_text",
  "required": true
}'
Response · 201
{
  "data": {
    "id": "q_1",
    "event_id": "evt_7f3ab1",
    "label": "What are you building?",
    "type": "long_text",
    "options": [],
    "required": true,
    "sort_order": 0,
    "created_at": "2026-10-01T17:07:00.000Z"
  }
}
GET/api/v1/questions/:id

Retrieve a question

Returns { data: Question }.
curl "https://valore.app/api/v1/questions/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "q_1",
    "event_id": "evt_7f3ab1",
    "label": "What are you building?",
    "type": "long_text",
    "options": [],
    "required": true,
    "sort_order": 0,
    "created_at": "2026-10-01T17:07:00.000Z"
  }
}
PATCH/api/v1/questions/:id

Update a question

Body parameters
label
string
type
string
textlong_textselectmulti_selectcheckboxurlphonecompanysocialterms
options
string[]
For select / multi_select.
required
boolean
Returns { data: Question }.
curl -X PATCH "https://valore.app/api/v1/questions/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "required": false
}'
Response · 200
{
  "data": {
    "id": "q_1",
    "event_id": "evt_7f3ab1",
    "label": "What are you building?",
    "type": "long_text",
    "options": [],
    "required": true,
    "sort_order": 0,
    "created_at": "2026-10-01T17:07:00.000Z"
  }
}
DELETE/api/v1/questions/:id

Delete a question

Returns { data }.
curl -X DELETE "https://valore.app/api/v1/questions/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "q_1",
    "deleted": true
  }
}

Orders

Ticket purchases, and full or partial refunds. Amounts are integer cents.

GET/api/v1/events/:id/orders

List orders

Query parameters
status
string
pendingpaidpartially_refundedrefundedfailed
guest_id
string
limit
integerdefault 25
Page size, 1–100.
cursor
string
The next_cursor from the previous page.
Returns a page of Order objects as { data, next_cursor }.
curl "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/orders?status=pending&guest_id=demo" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "ord_9",
      "number": 1042,
      "number_label": "#1042",
      "event_id": "evt_7f3ab1",
      "guest_id": "gst_2c9d10",
      "email": "ada@example.com",
      "name": "Ada Lovelace",
      "status": "paid",
      "subtotal_cents": 2500,
      "discount_cents": 500,
      "fee_cents": 0,
      "tax_cents": 0,
      "total_cents": 2000,
      "refunded_cents": 0,
      "currency": "usd",
      "coupon_code": "FRIENDS20",
      "paid_at": "2026-10-03T21:15:00.000Z",
      "created_at": "2026-10-03T21:14:10.000Z"
    }
  ],
  "next_cursor": "ord_9"
}
GET/api/v1/orders/:id

Retrieve an order

Returns { data: Order }.
curl "https://valore.app/api/v1/orders/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "ord_9",
    "number": 1042,
    "number_label": "#1042",
    "event_id": "evt_7f3ab1",
    "guest_id": "gst_2c9d10",
    "email": "ada@example.com",
    "name": "Ada Lovelace",
    "status": "paid",
    "subtotal_cents": 2500,
    "discount_cents": 500,
    "fee_cents": 0,
    "tax_cents": 0,
    "total_cents": 2000,
    "refunded_cents": 0,
    "currency": "usd",
    "coupon_code": "FRIENDS20",
    "paid_at": "2026-10-03T21:15:00.000Z",
    "created_at": "2026-10-03T21:14:10.000Z"
  }
}
POST/api/v1/orders/:id/refund

Refund an order

Refund a paid order in full (no `amount_cents`) or partially, through Stripe. The guest's registration is unchanged; set their status separately if they're no longer coming.

  • Moves real money for live-mode calendars. A full refund is safe to retry; a partial refund is not.
Body parameters
amount_cents
integer
Partial refund in cents. Omit to refund what's left.
reason
string
requested_by_customerduplicate
Returns { data: Order }.
curl -X POST "https://valore.app/api/v1/orders/EVENT_OR_RESOURCE_ID/refund" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "amount_cents": 1500
}'
Response · 200
{
  "data": {
    "id": "ord_9",
    "number": 1042,
    "number_label": "#1042",
    "event_id": "evt_7f3ab1",
    "guest_id": "gst_2c9d10",
    "email": "ada@example.com",
    "name": "Ada Lovelace",
    "status": "partially_refunded",
    "subtotal_cents": 2500,
    "discount_cents": 500,
    "fee_cents": 0,
    "tax_cents": 0,
    "total_cents": 2000,
    "refunded_cents": 1500,
    "currency": "usd",
    "coupon_code": "FRIENDS20",
    "paid_at": "2026-10-03T21:15:00.000Z",
    "created_at": "2026-10-03T21:14:10.000Z"
  }
}

Feedback

Post-event ratings (1–5) and comments.

GET/api/v1/events/:id/feedback

List feedback

  • Adds summary: { count, average_rating }.
Query parameters
limit
integerdefault 25
Page size, 1–100.
cursor
string
The next_cursor from the previous page.
Returns a page of Feedback objects as { data, next_cursor }.
curl "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/feedback" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "fb_1",
      "event_id": "evt_7f3ab1",
      "guest_id": "gst_2c9d10",
      "guest_name": "Ada Lovelace",
      "guest_email": "ada@example.com",
      "rating": 5,
      "comment": "Best demo night yet.",
      "created_at": "2026-11-06T18:00:00.000Z"
    }
  ],
  "next_cursor": null,
  "summary": {
    "count": 31,
    "average_rating": 4.6
  }
}

Photos

Event photo albums. Featured photos show under "Event photos" on the page; guests' uploads start in "Community photos".

GET/api/v1/events/:id/photos

List photos

The event's album, newest first. Host uploads start `featured` ("Event photos" on the page); guest uploads start in "Community photos" until a host features them.

Query parameters
featured
boolean
Only featured (true) or only community (false) photos.
hidden
boolean
Only hidden (true) or only visible (false) photos.
limit
integerdefault 25
Page size, 1–100.
cursor
string
The next_cursor from the previous page.
Returns a page of Photo objects as { data, next_cursor }.
curl "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/photos?featured=demo&hidden=demo" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "ph_1",
      "event_id": "evt_7f3ab1",
      "url": "https://…/photo.jpg",
      "width": 1600,
      "height": 1067,
      "caption": "Team Lumen on stage",
      "uploader_name": "Ada Lovelace",
      "featured": false,
      "hidden": false,
      "created_at": "2026-11-05T04:12:00.000Z"
    }
  ],
  "next_cursor": null
}
PATCH/api/v1/photos/:id

Update a photo

Feature or un-feature a photo, hide it, or edit its caption.

Body parameters
featured
boolean
Show it in the event page's "Event photos" section; false moves it to "Community photos".
hidden
boolean
Hidden photos are only visible to hosts.
caption
string
Returns { data: Photo }.
curl -X PATCH "https://valore.app/api/v1/photos/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "featured": true
}'
Response · 200
{
  "data": {
    "id": "ph_1",
    "event_id": "evt_7f3ab1",
    "url": "https://…/photo.jpg",
    "width": 1600,
    "height": 1067,
    "caption": "Team Lumen on stage",
    "uploader_name": "Ada Lovelace",
    "featured": true,
    "hidden": false,
    "created_at": "2026-11-05T04:12:00.000Z"
  }
}
DELETE/api/v1/photos/:id

Delete a photo

Removes the photo and its file. To keep it but take it off the page, PATCH `hidden: true` instead.

Returns { data }.
curl -X DELETE "https://valore.app/api/v1/photos/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "ph_1",
    "deleted": true
  }
}

Polls

Polls and "Find a time" date polls on the event page, with live results.

GET/api/v1/events/:id/polls

List polls

Polls and "Find a time" date polls on the event page, with live results.

Returns { data: Poll[] }.
curl "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/polls" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "poll_1",
      "kind": "poll",
      "question": "Pizza or tacos?",
      "allow_multiple": false,
      "closed": false,
      "chosen_option_id": null,
      "voter_count": 31,
      "options": [
        {
          "id": "opt_1",
          "label": "Pizza",
          "starts_at": null,
          "ends_at": null,
          "yes": 12,
          "maybe": 0,
          "no": 0
        },
        {
          "id": "opt_2",
          "label": "Tacos",
          "starts_at": null,
          "ends_at": null,
          "yes": 19,
          "maybe": 0,
          "no": 0
        }
      ],
      "created_at": "2026-10-25T18:00:00.000Z"
    }
  ]
}
POST/api/v1/events/:id/polls

Create a poll

Body parameters
kind
stringdefault poll
date is a "Find a time" poll: guests answer yes / maybe / no for each time option.
polldate
question
stringrequired
allow_multiple
booleandefault false
Let guests pick more than one option (poll only).
options
object[]required
Returns { data: Poll } with status 201.
curl -X POST "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/polls" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "question": "Pizza or tacos?",
  "options": [
    {
      "label": "Pizza"
    },
    {
      "label": "Tacos"
    }
  ]
}'
Response · 201
{
  "data": {
    "id": "poll_1",
    "kind": "poll",
    "question": "Pizza or tacos?",
    "allow_multiple": false,
    "closed": false,
    "chosen_option_id": null,
    "voter_count": 31,
    "options": [
      {
        "id": "opt_1",
        "label": "Pizza",
        "starts_at": null,
        "ends_at": null,
        "yes": 12,
        "maybe": 0,
        "no": 0
      },
      {
        "id": "opt_2",
        "label": "Tacos",
        "starts_at": null,
        "ends_at": null,
        "yes": 19,
        "maybe": 0,
        "no": 0
      }
    ],
    "created_at": "2026-10-25T18:00:00.000Z"
  }
}
PATCH/api/v1/polls/:id

Edit or close a poll

Body parameters
question
string
closed
boolean
Closed polls keep their results but take no more votes.
Returns { data: Poll }.
curl -X PATCH "https://valore.app/api/v1/polls/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "closed": true
}'
Response · 200
{
  "data": {
    "id": "poll_1",
    "kind": "poll",
    "question": "Pizza or tacos?",
    "allow_multiple": false,
    "closed": true,
    "chosen_option_id": null,
    "voter_count": 31,
    "options": [
      {
        "id": "opt_1",
        "label": "Pizza",
        "starts_at": null,
        "ends_at": null,
        "yes": 12,
        "maybe": 0,
        "no": 0
      },
      {
        "id": "opt_2",
        "label": "Tacos",
        "starts_at": null,
        "ends_at": null,
        "yes": 19,
        "maybe": 0,
        "no": 0
      }
    ],
    "created_at": "2026-10-25T18:00:00.000Z"
  }
}
DELETE/api/v1/polls/:id

Delete a poll

Returns { data }.
curl -X DELETE "https://valore.app/api/v1/polls/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "poll_1",
    "deleted": true
  }
}

Discussion

The event page's discussion. The key posts as a host and can pin, hide or delete comments.

GET/api/v1/events/:id/comments

List the discussion

Top-level comments (oldest first) with their replies, reactions, and pinned / hidden state. Hidden comments are included because the key acts as a host.

Returns { data: Comment[] }.
curl "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/comments" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "cmt_1",
      "parent_id": null,
      "name": "Ada Lovelace",
      "body": "Doors are open! Head to the 3rd floor.",
      "image_url": null,
      "is_host": true,
      "pinned": true,
      "hidden": false,
      "reactions": [
        {
          "emoji": "🎉",
          "count": 6
        }
      ],
      "replies": [],
      "created_at": "2026-11-05T02:02:00.000Z"
    }
  ],
  "comments_enabled": true
}
POST/api/v1/events/:id/comments

Post a comment

Posts as the key's owner, marked as a host. Pass `parent_id` to reply. Guests who follow the discussion are notified.

Body parameters
body
stringrequired
parent_id
string
Reply to this comment.
Returns { data: Comment } with status 201.
curl -X POST "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/comments" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "body": "Doors are open! Head to the 3rd floor."
}'
Response · 201
{
  "data": {
    "id": "cmt_1",
    "parent_id": null,
    "name": "Ada Lovelace",
    "body": "Doors are open! Head to the 3rd floor.",
    "image_url": null,
    "is_host": true,
    "pinned": true,
    "hidden": false,
    "reactions": [
      {
        "emoji": "🎉",
        "count": 6
      }
    ],
    "replies": [],
    "created_at": "2026-11-05T02:02:00.000Z"
  }
}
PATCH/api/v1/comments/:id

Pin or hide a comment

Body parameters
pinned
boolean
hidden
boolean
Hidden comments are only visible to hosts.
Returns { data }.
curl -X PATCH "https://valore.app/api/v1/comments/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "pinned": true
}'
Response · 200
{
  "data": {
    "id": "cmt_1",
    "pinned": true,
    "hidden": false
  }
}
DELETE/api/v1/comments/:id

Delete a comment

Deletes the comment and its replies. To keep it but take it off the page, PATCH `hidden: true` instead.

Returns { data }.
curl -X DELETE "https://valore.app/api/v1/comments/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "cmt_1",
    "deleted": true
  }
}

Blasts & newsletters

Email updates in markdown: blasts to an event's guests, and newsletters to the calendar's subscribers.

GET/api/v1/events/:id/blasts

List blasts

Query parameters
limit
integerdefault 25
Page size, 1–100.
cursor
string
The next_cursor from the previous page.
Returns a page of Blast objects as { data, next_cursor }.
curl "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/blasts" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "bl_4",
      "event_id": "evt_7f3ab1",
      "calendar_id": null,
      "kind": "event_blast",
      "subject": "Parking + doors at 6",
      "body": "Doors open at **6pm**. Parking is free on Howard after 6.",
      "audience": [
        "going"
      ],
      "status": "sent",
      "channel": "email",
      "scheduled_at": null,
      "sent_at": "2026-11-04T17:00:00.000Z",
      "recipient_count": 84,
      "stats": {
        "delivered": 84,
        "opened": 61,
        "clicked": 9
      },
      "created_at": "2026-11-04T16:55:00.000Z",
      "updated_at": "2026-11-04T17:00:00.000Z"
    }
  ],
  "next_cursor": null
}
POST/api/v1/events/:id/blasts

Create (and optionally send) a blast

  • Without send or scheduled_at the blast is saved as a draft you can send later.
Body parameters
subject
stringrequired
body
stringrequired
Markdown, up to 20,000 characters.
audience
string[]default ["going"]
Who receives it.
goingpending_approvalwaitlistinviteddeclinednot_goingchecked_innot_checked_in
send
booleandefault false
Send immediately.
scheduled_at
datetime
Send later (must be in the future).
Returns { data: Blast } with status 201.
curl -X POST "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/blasts" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "subject": "Parking + doors at 6",
  "body": "Doors open at **6pm**. Parking is free on Howard after 6.",
  "audience": [
    "going"
  ],
  "send": true
}'
Response · 201
{
  "data": {
    "id": "bl_4",
    "event_id": "evt_7f3ab1",
    "calendar_id": null,
    "kind": "event_blast",
    "subject": "Parking + doors at 6",
    "body": "Doors open at **6pm**. Parking is free on Howard after 6.",
    "audience": [
      "going"
    ],
    "status": "sent",
    "channel": "email",
    "scheduled_at": null,
    "sent_at": "2026-11-04T17:00:00.000Z",
    "recipient_count": 84,
    "stats": {
      "delivered": 84,
      "opened": 61,
      "clicked": 9
    },
    "created_at": "2026-11-04T16:55:00.000Z",
    "updated_at": "2026-11-04T17:00:00.000Z"
  }
}
GET/api/v1/blasts/:id

Retrieve a blast

Returns { data: Blast }.
curl "https://valore.app/api/v1/blasts/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "bl_4",
    "event_id": "evt_7f3ab1",
    "calendar_id": null,
    "kind": "event_blast",
    "subject": "Parking + doors at 6",
    "body": "Doors open at **6pm**. Parking is free on Howard after 6.",
    "audience": [
      "going"
    ],
    "status": "sent",
    "channel": "email",
    "scheduled_at": null,
    "sent_at": "2026-11-04T17:00:00.000Z",
    "recipient_count": 84,
    "stats": {
      "delivered": 84,
      "opened": 61,
      "clicked": 9
    },
    "created_at": "2026-11-04T16:55:00.000Z",
    "updated_at": "2026-11-04T17:00:00.000Z"
  }
}
POST/api/v1/blasts/:id/send

Send a draft now

Returns { data: Blast }.
curl -X POST "https://valore.app/api/v1/blasts/EVENT_OR_RESOURCE_ID/send" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "bl_4",
    "event_id": "evt_7f3ab1",
    "calendar_id": null,
    "kind": "event_blast",
    "subject": "Parking + doors at 6",
    "body": "Doors open at **6pm**. Parking is free on Howard after 6.",
    "audience": [
      "going"
    ],
    "status": "sent",
    "channel": "email",
    "scheduled_at": null,
    "sent_at": "2026-11-04T17:00:00.000Z",
    "recipient_count": 84,
    "stats": {
      "delivered": 84,
      "opened": 61,
      "clicked": 9
    },
    "created_at": "2026-11-04T16:55:00.000Z",
    "updated_at": "2026-11-04T17:00:00.000Z"
  }
}
GET/api/v1/newsletters

List newsletters

Emails to the calendar's subscribers, newest first. Retrieve and send them with the blast endpoints (`/blasts/:id`).

Query parameters
limit
integerdefault 25
Page size, 1–100.
cursor
string
The next_cursor from the previous page.
Returns a page of Blast objects as { data, next_cursor }.
curl "https://valore.app/api/v1/newsletters" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "bl_4",
      "event_id": null,
      "calendar_id": "cal_9x1kq2",
      "kind": "newsletter",
      "subject": "Parking + doors at 6",
      "body": "Doors open at **6pm**. Parking is free on Howard after 6.",
      "audience": [],
      "status": "sent",
      "channel": "email",
      "scheduled_at": null,
      "sent_at": "2026-11-04T17:00:00.000Z",
      "recipient_count": 84,
      "stats": {
        "delivered": 84,
        "opened": 61,
        "clicked": 9
      },
      "created_at": "2026-11-04T16:55:00.000Z",
      "updated_at": "2026-11-04T17:00:00.000Z"
    }
  ],
  "next_cursor": null
}
POST/api/v1/newsletters

Create (and optionally send) a newsletter

  • Without send or scheduled_at the newsletter is saved as a draft; send it later with POST /blasts/:id/send.
Body parameters
subject
stringrequired
body
stringrequired
Markdown, up to 20,000 characters.
audience
string[]default []
Subscriber tags. Empty sends to every subscriber.
send
booleandefault false
Send immediately.
scheduled_at
datetime
Send later (must be in the future).
Returns { data: Blast } with status 201.
curl -X POST "https://valore.app/api/v1/newsletters" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "subject": "What'\''s on in November",
  "body": "Three events this month, starting with **Demo Night** on the 5th.",
  "audience": [],
  "send": false
}'
Response · 201
{
  "data": {
    "id": "bl_4",
    "event_id": null,
    "calendar_id": "cal_9x1kq2",
    "kind": "newsletter",
    "subject": "Parking + doors at 6",
    "body": "Doors open at **6pm**. Parking is free on Howard after 6.",
    "audience": [],
    "status": "sent",
    "channel": "email",
    "scheduled_at": null,
    "sent_at": "2026-11-04T17:00:00.000Z",
    "recipient_count": 84,
    "stats": {
      "delivered": 84,
      "opened": 61,
      "clicked": 9
    },
    "created_at": "2026-11-04T16:55:00.000Z",
    "updated_at": "2026-11-04T17:00:00.000Z"
  }
}

People (CRM)

Everyone in the calendar's CRM, with tags, engagement stats, notes and a timeline. A person is the same record as a subscriber.

GET/api/v1/people

Search people

Everyone in the calendar's CRM (subscribers, past guests, imports) with engagement stats. Filter by tags, attendance, spend, city, activity, events or a saved segment.

  • Paged by offset (not a cursor): the response has total and next_offset.
Query parameters
q
string
Matches name, email, company or phone.
tags
string
Comma-separated tags.
tag_mode
string
anyall
exclude_tags
string
Comma-separated tags.
attended_min
integer
registered_min
integer
spent_min_cents
integer
city
string
last_active_days
integer
event_ids
string
Comma-separated event ids.
event_mode
string
registeredattended
sms_opt_in
boolean
has_phone
boolean
status
string
allsubscribedunsubscribedblocked
source
string
segment_id
string
Only people in this saved segment (combined with the other filters).
sort
stringdefault last_activity_at
Sort key.
nameemailcompanyevents_registeredevents_attendedtotal_spent_centslast_activity_atcreated_at
order
stringdefault desc
ascdesc
limit
integerdefault 25
Page size, 1–100.
offset
integerdefault 0
Skip this many (use next_offset from the previous page).
Returns { data: Person[] }.
curl "https://valore.app/api/v1/people?q=demo&tags=demo" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "sub_77",
      "email": "ada@example.com",
      "name": "Ada Lovelace",
      "phone": "+14155550123",
      "company": "Analytical Engines",
      "job_title": "Founder",
      "city": "San Francisco",
      "tags": [
        "vip",
        "speaker"
      ],
      "status": "subscribed",
      "blocked": false,
      "sms_opt_in": true,
      "source": "event",
      "events_registered": 4,
      "events_attended": 3,
      "total_spent_cents": 6000,
      "has_account": true,
      "last_activity_at": "2026-11-05T02:41:00.000Z",
      "created_at": "2026-03-02T19:00:00.000Z"
    }
  ],
  "total": 1,
  "next_offset": null
}
POST/api/v1/people

Add a person

Adds a contact to the CRM (and the calendar's subscribers). Adding an existing email updates that person instead.

Body parameters
email
emailrequired
name
string
phone
string
With country code, e.g. +1 415 555 0123.
company
string
job_title
string
city
string
notes
string
Free-text notes on the profile (separate from timeline notes).
tags
string[]
sms_opt_in
boolean
Only set true with the person's consent to receive texts.
Returns { data: Person } with status 201.
curl -X POST "https://valore.app/api/v1/people" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "grace@example.com",
  "name": "Grace Hopper",
  "company": "Navy",
  "tags": [
    "vip"
  ]
}'
Response · 201
{
  "data": {
    "id": "sub_77",
    "email": "ada@example.com",
    "name": "Ada Lovelace",
    "phone": "+14155550123",
    "company": "Analytical Engines",
    "job_title": "Founder",
    "city": "San Francisco",
    "tags": [
      "vip",
      "speaker"
    ],
    "status": "subscribed",
    "blocked": false,
    "sms_opt_in": true,
    "source": "event",
    "events_registered": 4,
    "events_attended": 3,
    "total_spent_cents": 6000,
    "has_account": true,
    "last_activity_at": "2026-11-05T02:41:00.000Z",
    "created_at": "2026-03-02T19:00:00.000Z"
  }
}
GET/api/v1/people/:id

Retrieve a person's profile

The contact plus stats (attendance rate, lifetime value), registrations, orders, messages sent to them, the activity timeline (notes, check-ins, tag changes) and the segments they're in.

Returns { data }.
curl "https://valore.app/api/v1/people/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "contact": {
      "id": "sub_77",
      "email": "ada@example.com",
      "name": "Ada Lovelace",
      "phone": "+14155550123",
      "company": "Analytical Engines",
      "job_title": "Founder",
      "city": "San Francisco",
      "tags": [
        "vip",
        "speaker"
      ],
      "status": "subscribed",
      "blocked": false,
      "sms_opt_in": true,
      "source": "event",
      "events_registered": 4,
      "events_attended": 3,
      "total_spent_cents": 6000,
      "has_account": true,
      "last_activity_at": "2026-11-05T02:41:00.000Z",
      "created_at": "2026-03-02T19:00:00.000Z"
    },
    "notes": null,
    "stats": {
      "events_registered": 4,
      "events_attended": 3,
      "attendance_rate": 75,
      "total_spent_cents": 6000,
      "upcoming": 1,
      "currency": "usd"
    },
    "registrations": [
      {
        "guest_id": "gst_2c9d10",
        "event_id": "evt_7f3ab1",
        "title": "Demo Night · November",
        "status": "GOING",
        "checked_in_at": null
      }
    ],
    "orders": [],
    "messages": [
      {
        "id": "md_1",
        "kind": "REMINDER",
        "channel": "EMAIL",
        "subject": "Tomorrow: Demo Night",
        "opened_at": "2026-11-04T17:20:00.000Z"
      }
    ],
    "activities": [
      {
        "id": "act_1",
        "kind": "note",
        "summary": "Wants to sponsor the spring series",
        "actor_name": "Ada Lovelace",
        "created_at": "2026-10-30T18:00:00.000Z"
      }
    ],
    "segments": [
      {
        "id": "seg_1",
        "name": "Regulars"
      }
    ]
  }
}
PATCH/api/v1/people/:id

Update a person

Body parameters
email
email
name
string
phone
string
With country code, e.g. +1 415 555 0123.
company
string
job_title
string
city
string
notes
string
Free-text notes on the profile (separate from timeline notes).
tags
string[]
sms_opt_in
boolean
Only set true with the person's consent to receive texts.
status
string
subscribedunsubscribed
blocked
boolean
Blocked people can't register for the calendar's events or receive its email.
Returns { data: Person }.
curl -X PATCH "https://valore.app/api/v1/people/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "company": "Analytical Engines",
  "tags": [
    "vip",
    "speaker"
  ]
}'
Response · 200
{
  "data": {
    "id": "sub_77",
    "email": "ada@example.com",
    "name": "Ada Lovelace",
    "phone": "+14155550123",
    "company": "Analytical Engines",
    "job_title": "Founder",
    "city": "San Francisco",
    "tags": [
      "vip",
      "speaker"
    ],
    "status": "subscribed",
    "blocked": false,
    "sms_opt_in": true,
    "source": "event",
    "events_registered": 4,
    "events_attended": 3,
    "total_spent_cents": 6000,
    "has_account": true,
    "last_activity_at": "2026-11-05T02:41:00.000Z",
    "created_at": "2026-03-02T19:00:00.000Z"
  }
}
POST/api/v1/people/:id/notes

Add a note to a person's timeline

Body parameters
body
stringrequired
Returns { data } with status 201.
curl -X POST "https://valore.app/api/v1/people/EVENT_OR_RESOURCE_ID/notes" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "body": "Wants to sponsor the spring series"
}'
Response · 201
{
  "data": {
    "id": "act_1",
    "body": "Wants to sponsor the spring series",
    "created_at": "2026-10-30T18:00:00.000Z"
  }
}
DELETE/api/v1/people/:id/notes/:noteId

Delete a note

Returns { data }.
curl -X DELETE "https://valore.app/api/v1/people/EVENT_OR_RESOURCE_ID/notes/NOTE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "act_1",
    "deleted": true
  }
}
POST/api/v1/people/bulk

Tag, untag, unsubscribe or block people in bulk

Act on explicit `ids`, or on everyone matching `filters`. `delete` removes the people from the CRM entirely.

Body parameters
action
stringrequired
taguntagunsubscribeblockunblocksms_offdelete
ids
string[]
filters
object
Who to include. Omit (or {}) for everyone.
tags
string[]
For tag / untag.
Returns { data }.
curl -X POST "https://valore.app/api/v1/people/bulk" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "action": "tag",
  "tags": [
    "spring-sponsors"
  ],
  "ids": [
    "sub_77"
  ]
}'
Response · 200
{
  "data": {
    "action": "tag",
    "affected": 1
  }
}
GET/api/v1/people/duplicates

Find likely duplicates

Groups of people who share a phone number or full name (different emails). Merge them with `POST /people/:id/merge`.

Returns { data }.
curl "https://valore.app/api/v1/people/duplicates" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "reason": "Same name",
      "people": [
        {
          "id": "sub_77",
          "email": "ada@example.com"
        },
        {
          "id": "sub_78",
          "email": "ada@work.example"
        }
      ]
    }
  ]
}
POST/api/v1/people/:id/merge

Merge duplicates into a person

Moves registrations and timeline from each duplicate onto this person, fills blank fields, unions tags, then deletes the duplicates.

Body parameters
duplicate_ids
string[]required
Returns { data: Person }.
curl -X POST "https://valore.app/api/v1/people/EVENT_OR_RESOURCE_ID/merge" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "duplicate_ids": [
    "sub_78"
  ]
}'
Response · 200
{
  "data": {
    "id": "sub_77",
    "email": "ada@example.com",
    "name": "Ada Lovelace",
    "phone": "+14155550123",
    "company": "Analytical Engines",
    "job_title": "Founder",
    "city": "San Francisco",
    "tags": [
      "vip",
      "speaker"
    ],
    "status": "subscribed",
    "blocked": false,
    "sms_opt_in": true,
    "source": "event",
    "events_registered": 4,
    "events_attended": 3,
    "total_spent_cents": 6000,
    "has_account": true,
    "last_activity_at": "2026-11-05T02:41:00.000Z",
    "created_at": "2026-03-02T19:00:00.000Z"
  }
}

Segments

Saved people filters that update as people match. Use them to search people and as campaign audiences.

GET/api/v1/segments

List segments

Saved people filters, with how many people match each right now.

Returns { data: Segment[] }.
curl "https://valore.app/api/v1/segments" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "seg_1",
      "name": "Regulars",
      "filters": {
        "attended_min": 3
      },
      "count": 87,
      "updated_at": "2026-10-01T17:00:00.000Z"
    }
  ]
}
POST/api/v1/segments

Create a segment

Body parameters
name
stringrequired
filters
objectrequired
Who to include. Omit (or {}) for everyone.
Returns { data: Segment } with status 201.
curl -X POST "https://valore.app/api/v1/segments" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Regulars",
  "filters": {
    "attended_min": 3
  }
}'
Response · 201
{
  "data": {
    "id": "seg_1",
    "name": "Regulars",
    "filters": {
      "attended_min": 3
    },
    "count": 87,
    "updated_at": "2026-10-01T17:00:00.000Z"
  }
}
GET/api/v1/segments/:id

Retrieve a segment

List the people in it with `GET /people?segment_id=…`.

Returns { data: Segment }.
curl "https://valore.app/api/v1/segments/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "seg_1",
    "name": "Regulars",
    "filters": {
      "attended_min": 3
    },
    "count": 87,
    "updated_at": "2026-10-01T17:00:00.000Z"
  }
}
PATCH/api/v1/segments/:id

Update a segment

Body parameters
name
string
filters
object
Replaces the saved filters.
Returns { data: Segment }.
curl -X PATCH "https://valore.app/api/v1/segments/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "filters": {
    "attended_min": 4
  }
}'
Response · 200
{
  "data": {
    "id": "seg_1",
    "name": "Regulars",
    "filters": {
      "attended_min": 3
    },
    "count": 87,
    "updated_at": "2026-10-01T17:00:00.000Z"
  }
}
DELETE/api/v1/segments/:id

Delete a segment

Deletes the saved filter only; nobody is removed from the CRM.

Returns { data }.
curl -X DELETE "https://valore.app/api/v1/segments/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "seg_1",
    "deleted": true
  }
}

Campaigns

Email and text campaigns to any CRM audience: everyone, tags, a segment, chosen people, an event's guests or filters.

GET/api/v1/campaigns

List campaigns

Email and text campaigns (and newsletters) from this calendar, newest first, with the audience described and delivery stats.

Query parameters
channel
string
emailsms
Returns { data }.
curl "https://valore.app/api/v1/campaigns?channel=email" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "bl_9",
      "channel": "email",
      "subject": "Spring series tickets",
      "status": "sent",
      "audience_label": "Segment: Regulars",
      "sent_at": "2026-10-20T17:00:00.000Z",
      "recipient_count": 212,
      "email": {
        "delivered": 210,
        "opened": 131,
        "clicked": 40
      },
      "sms": null
    }
  ]
}
POST/api/v1/campaigns

Create (and optionally send) a campaign

An email or text to any audience in the CRM: everyone, tags, a segment, chosen people, an event's guests, or filters.

  • Without send or scheduled_at it's saved as a draft. Preview the audience with POST /campaigns/preview and send yourself a test with POST /campaigns/test first.
Body parameters
channel
stringdefault email
sms needs people's SMS consent, and texting must be enabled for your account.
emailsms
subject
string
Required for email.
body
stringrequired
Markdown for email; plain text (up to 1,000 characters) for SMS. Merge fields: {first_name}, {event_title}, {event_link}.
audience
objectrequired
The audience.
merge_event_id
string
Event used for {event_title} / {event_link}. Defaults to the next upcoming one.
send
booleandefault false
Send immediately.
scheduled_at
datetime
Send later (must be in the future).
Returns { data: Blast } with status 201.
curl -X POST "https://valore.app/api/v1/campaigns" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "channel": "email",
  "subject": "Spring series tickets",
  "body": "Hi {first_name}, tickets for the spring series are live.",
  "audience": {
    "type": "segment",
    "segment_id": "seg_1"
  }
}'
Response · 201
{
  "data": {
    "id": "bl_4",
    "event_id": null,
    "calendar_id": "cal_9x1kq2",
    "kind": "newsletter",
    "subject": "Parking + doors at 6",
    "body": "Doors open at **6pm**. Parking is free on Howard after 6.",
    "audience": [
      "going"
    ],
    "status": "draft",
    "channel": "email",
    "scheduled_at": null,
    "sent_at": null,
    "recipient_count": 0,
    "stats": {
      "delivered": 84,
      "opened": 61,
      "clicked": 9
    },
    "created_at": "2026-11-04T16:55:00.000Z",
    "updated_at": "2026-11-04T17:00:00.000Z"
  }
}
POST/api/v1/campaigns/preview

Preview an audience

How many people a campaign would reach, how many match but can't receive it (unsubscribed, no SMS consent…), and a sample. Sends nothing.

Body parameters
channel
stringdefault email
emailsms
audience
objectrequired
The audience.
Returns { data }.
curl -X POST "https://valore.app/api/v1/campaigns/preview" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "channel": "email",
  "audience": {
    "type": "tags",
    "tags": [
      "vip"
    ]
  }
}'
Response · 200
{
  "data": {
    "count": 41,
    "matched": 44,
    "excluded": {
      "unsubscribed": 3
    },
    "sample": [
      {
        "name": "Ada Lovelace",
        "email": "ada@example.com",
        "phone": null
      }
    ]
  }
}
POST/api/v1/campaigns/test

Send yourself a test

Sends the message, with merge fields filled in, to the key owner's email (or phone, for SMS) only.

Body parameters
channel
stringdefault email
emailsms
subject
string
body
stringrequired
merge_event_id
string
Returns { data }.
curl -X POST "https://valore.app/api/v1/campaigns/test" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "channel": "email",
  "subject": "Spring series tickets",
  "body": "Hi {first_name}…"
}'
Response · 200
{
  "data": {
    "status": "sent",
    "to": "ada@example.com"
  }
}
POST/api/v1/campaigns/:id/send

Send a draft campaign now

Returns { data: Blast }.
curl -X POST "https://valore.app/api/v1/campaigns/EVENT_OR_RESOURCE_ID/send" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "bl_4",
    "event_id": null,
    "calendar_id": "cal_9x1kq2",
    "kind": "newsletter",
    "subject": "Parking + doors at 6",
    "body": "Doors open at **6pm**. Parking is free on Howard after 6.",
    "audience": [
      "going"
    ],
    "status": "sent",
    "channel": "email",
    "scheduled_at": null,
    "sent_at": "2026-11-04T17:00:00.000Z",
    "recipient_count": 84,
    "stats": {
      "delivered": 84,
      "opened": 61,
      "clicked": 9
    },
    "created_at": "2026-11-04T16:55:00.000Z",
    "updated_at": "2026-11-04T17:00:00.000Z"
  }
}

Deals

The sponsor and partner pipeline: lead, contacted, negotiating, committed, won, lost.

GET/api/v1/deals

List deals

The sponsor / partner pipeline, with totals per stage in `pipeline`.

Query parameters
stage
string
leadcontactednegotiatingcommittedwonlost
event_id
string
Returns { data: Deal[] }.
curl "https://valore.app/api/v1/deals?stage=lead&event_id=demo" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "deal_1",
      "name": "Acme · Spring series",
      "company": "Acme",
      "contact_name": "Grace Hopper",
      "contact_email": "grace@acme.example",
      "stage": "negotiating",
      "value_cents": 500000,
      "notes": null,
      "event_id": null,
      "event_title": null,
      "due_at": "2026-11-20T17:00:00.000Z",
      "created_at": "2026-10-12T16:00:00.000Z",
      "updated_at": "2026-10-28T21:00:00.000Z"
    }
  ],
  "pipeline": {
    "by_stage": {
      "LEAD": {
        "count": 0,
        "value_cents": 0
      },
      "NEGOTIATING": {
        "count": 1,
        "value_cents": 500000
      }
    },
    "open_value_cents": 500000,
    "weighted_value_cents": 250000
  }
}
POST/api/v1/deals

Create a deal

Body parameters
name
stringrequired
e.g. "Acme · Spring series sponsor".
company
string
contact_name
string
contact_email
string
stage
string
Defaults to lead.
leadcontactednegotiatingcommittedwonlost
value_cents
integer
notes
string
event_id
string
The event it's for, if any.
due_at
datetime
Returns { data: Deal } with status 201.
curl -X POST "https://valore.app/api/v1/deals" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Acme · Spring series",
  "company": "Acme",
  "value_cents": 500000,
  "stage": "contacted"
}'
Response · 201
{
  "data": {
    "id": "deal_1",
    "name": "Acme · Spring series",
    "company": "Acme",
    "contact_name": "Grace Hopper",
    "contact_email": "grace@acme.example",
    "stage": "negotiating",
    "value_cents": 500000,
    "notes": null,
    "event_id": null,
    "event_title": null,
    "due_at": "2026-11-20T17:00:00.000Z",
    "created_at": "2026-10-12T16:00:00.000Z",
    "updated_at": "2026-10-28T21:00:00.000Z"
  }
}
GET/api/v1/deals/:id

Retrieve a deal

Returns { data: Deal }.
curl "https://valore.app/api/v1/deals/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "deal_1",
    "name": "Acme · Spring series",
    "company": "Acme",
    "contact_name": "Grace Hopper",
    "contact_email": "grace@acme.example",
    "stage": "negotiating",
    "value_cents": 500000,
    "notes": null,
    "event_id": null,
    "event_title": null,
    "due_at": "2026-11-20T17:00:00.000Z",
    "created_at": "2026-10-12T16:00:00.000Z",
    "updated_at": "2026-10-28T21:00:00.000Z"
  }
}
PATCH/api/v1/deals/:id

Update a deal

Change any field, including `stage` to move it through the pipeline.

Body parameters
name
string
e.g. "Acme · Spring series sponsor".
company
string
contact_name
string
contact_email
string
stage
string
Defaults to lead.
leadcontactednegotiatingcommittedwonlost
value_cents
integer
notes
string
event_id
string
The event it's for, if any.
due_at
datetime
Returns { data: Deal }.
curl -X PATCH "https://valore.app/api/v1/deals/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "stage": "won"
}'
Response · 200
{
  "data": {
    "id": "deal_1",
    "name": "Acme · Spring series",
    "company": "Acme",
    "contact_name": "Grace Hopper",
    "contact_email": "grace@acme.example",
    "stage": "won",
    "value_cents": 500000,
    "notes": null,
    "event_id": null,
    "event_title": null,
    "due_at": "2026-11-20T17:00:00.000Z",
    "created_at": "2026-10-12T16:00:00.000Z",
    "updated_at": "2026-10-28T21:00:00.000Z"
  }
}
DELETE/api/v1/deals/:id

Delete a deal

Returns { data }.
curl -X DELETE "https://valore.app/api/v1/deals/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "deal_1",
    "deleted": true
  }
}

Memberships

Membership tiers (free, one-time, monthly or yearly) and the people who joined them.

GET/api/v1/membership-tiers

List membership tiers

Query parameters
include_inactive
boolean
Returns { data: MembershipTier[] }.
curl "https://valore.app/api/v1/membership-tiers?include_inactive=demo" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "tier_1",
      "name": "Supporter",
      "description": "Members-only events and early access.",
      "price_cents": 1000,
      "currency": "usd",
      "interval": "month",
      "require_approval": false,
      "active": true,
      "created_at": "2026-08-01T17:00:00.000Z"
    }
  ]
}
POST/api/v1/membership-tiers

Create a membership tier

Paid tiers need the calendar's Stripe account connected; members join from the calendar page.

Body parameters
name
stringrequired
description
string
price_cents
integer
Ignored for free tiers.
currency
stringdefault usd
interval
stringdefault free
How members pay.
freeone_timemonthyear
require_approval
boolean
Hosts approve each new member.
active
boolean
Inactive tiers can't be joined.
Returns { data: MembershipTier } with status 201.
curl -X POST "https://valore.app/api/v1/membership-tiers" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Supporter",
  "interval": "month",
  "price_cents": 1000
}'
Response · 201
{
  "data": {
    "id": "tier_1",
    "name": "Supporter",
    "description": "Members-only events and early access.",
    "price_cents": 1000,
    "currency": "usd",
    "interval": "month",
    "require_approval": false,
    "active": true,
    "created_at": "2026-08-01T17:00:00.000Z"
  }
}
PATCH/api/v1/membership-tiers/:id

Update a membership tier

  • Once members have paid, a tier's interval and currency are locked (409).
Body parameters
name
string
description
string
price_cents
integer
Ignored for free tiers.
currency
stringdefault usd
interval
stringdefault free
How members pay.
freeone_timemonthyear
require_approval
boolean
Hosts approve each new member.
active
boolean
Inactive tiers can't be joined.
Returns { data: MembershipTier }.
curl -X PATCH "https://valore.app/api/v1/membership-tiers/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "price_cents": 1200
}'
Response · 200
{
  "data": {
    "id": "tier_1",
    "name": "Supporter",
    "description": "Members-only events and early access.",
    "price_cents": 1200,
    "currency": "usd",
    "interval": "month",
    "require_approval": false,
    "active": true,
    "created_at": "2026-08-01T17:00:00.000Z"
  }
}
DELETE/api/v1/membership-tiers/:id

Delete a membership tier

A tier with members is archived (`archived: true`, inactive) instead of deleted; current members keep it.

Returns { data }.
curl -X DELETE "https://valore.app/api/v1/membership-tiers/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "tier_1",
    "deleted": true,
    "archived": false
  }
}
GET/api/v1/members

List members

Everyone with a membership on the calendar, pending approvals first.

Query parameters
status
string
pendingactivepast_duecanceled
tier_id
string
Returns { data: Membership[] }.
curl "https://valore.app/api/v1/members?status=pending&tier_id=demo" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "mbr_1",
      "email": "ada@example.com",
      "name": "Ada Lovelace",
      "status": "active",
      "tier_id": "tier_1",
      "tier_name": "Supporter",
      "has_account": true,
      "current_period_end": "2026-12-01T17:00:00.000Z",
      "created_at": "2026-09-01T17:00:00.000Z"
    }
  ]
}
POST/api/v1/members/:id/approve

Approve a pending member

The member is emailed. Approving an active member is a no-op.

Returns { data: Membership }.
curl -X POST "https://valore.app/api/v1/members/EVENT_OR_RESOURCE_ID/approve" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "mbr_1",
    "email": "ada@example.com",
    "name": "Ada Lovelace",
    "status": "active",
    "tier_id": "tier_1",
    "tier_name": "Supporter",
    "has_account": true,
    "current_period_end": "2026-12-01T17:00:00.000Z",
    "created_at": "2026-09-01T17:00:00.000Z"
  }
}
POST/api/v1/members/:id/cancel

Cancel a membership

Cancels now (paid subscriptions stop in Stripe immediately), or at the end of the paid period with `at_period_end`. A paid request that was never approved is refunded in full.

Body parameters
at_period_end
booleandefault false
Returns { data: Membership }.
curl -X POST "https://valore.app/api/v1/members/EVENT_OR_RESOURCE_ID/cancel" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "at_period_end": true
}'
Response · 200
{
  "data": {
    "id": "mbr_1",
    "email": "ada@example.com",
    "name": "Ada Lovelace",
    "status": "active",
    "tier_id": "tier_1",
    "tier_name": "Supporter",
    "has_account": true,
    "current_period_end": "2026-12-01T17:00:00.000Z",
    "created_at": "2026-09-01T17:00:00.000Z"
  }
}

Subscribers

People following the calendar (your newsletter audience).

GET/api/v1/subscribers

List subscribers

Query parameters
status
string
subscribedunsubscribed
tag
string
Only subscribers with this tag.
search
string
Name or email contains.
limit
integerdefault 25
Page size, 1–100.
cursor
string
The next_cursor from the previous page.
Returns a page of Subscriber objects as { data, next_cursor }.
curl "https://valore.app/api/v1/subscribers?status=subscribed&tag=demo" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "sub_77",
      "email": "linus@example.com",
      "name": "Linus",
      "tags": [
        "newsletter"
      ],
      "status": "subscribed",
      "source": "api",
      "created_at": "2026-10-01T12:00:00.000Z"
    }
  ],
  "next_cursor": "sub_77"
}
POST/api/v1/subscribers

Add a subscriber

  • Someone who unsubscribed stays unsubscribed; only they can opt back in.
Body parameters
email
emailrequired
name
string
tags
string[]
Up to 20 tags (lowercased).
Returns { data: Subscriber } with status 201.
curl -X POST "https://valore.app/api/v1/subscribers" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "linus@example.com",
  "name": "Linus",
  "tags": [
    "newsletter"
  ]
}'
Response · 201
{
  "data": {
    "id": "sub_77",
    "email": "linus@example.com",
    "name": "Linus",
    "tags": [
      "newsletter"
    ],
    "status": "subscribed",
    "source": "api",
    "created_at": "2026-10-01T12:00:00.000Z"
  }
}
POST/api/v1/subscribers/import

Bulk import subscribers

Body parameters
subscribers
object[]required
Up to 5,000 { email, name? } objects.
tags
string[]
Applied to everyone in the batch.
Returns { data } with status 201.
curl -X POST "https://valore.app/api/v1/subscribers/import" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "subscribers": [
    {
      "email": "a@example.com",
      "name": "A"
    },
    {
      "email": "b@example.com"
    }
  ],
  "tags": [
    "import-2026"
  ]
}'
Response · 201
{
  "data": {
    "added": 2,
    "updated": 0,
    "invalid": 0,
    "duplicates": 0,
    "opted_out": 0
  }
}
GET/api/v1/subscribers/:id

Retrieve a subscriber

Returns { data: Subscriber }.
curl "https://valore.app/api/v1/subscribers/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "sub_77",
    "email": "linus@example.com",
    "name": "Linus",
    "tags": [
      "newsletter"
    ],
    "status": "subscribed",
    "source": "api",
    "created_at": "2026-10-01T12:00:00.000Z"
  }
}
PATCH/api/v1/subscribers/:id

Update a subscriber

Body parameters
name
string
tags
string[]
Replaces the tag list.
status
string
Opt them out (honor unsubscribe requests this way).
subscribedunsubscribed
Returns { data: Subscriber }.
curl -X PATCH "https://valore.app/api/v1/subscribers/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "tags": [
    "newsletter",
    "vip"
  ]
}'
Response · 200
{
  "data": {
    "id": "sub_77",
    "email": "linus@example.com",
    "name": "Linus",
    "tags": [
      "newsletter"
    ],
    "status": "subscribed",
    "source": "api",
    "created_at": "2026-10-01T12:00:00.000Z"
  }
}
DELETE/api/v1/subscribers/:id

Delete a subscriber

  • Permanent. To honor an opt-out, PATCH status: "unsubscribed" instead.
Returns { data }.
curl -X DELETE "https://valore.app/api/v1/subscribers/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "sub_77",
    "deleted": true
  }
}

Do-not-invite list

Addresses no event on the calendar will invite. Check a list against it (and past bounces and opt-outs) with Check a list before inviting.

GET/api/v1/do-not-invite

List the do-not-invite list

Addresses no event on this calendar will ever send an invitation to. They can still register for public events.

Query parameters
search
string
Email contains.
limit
integerdefault 25
Page size, 1–100.
cursor
string
The next_cursor from the previous page.
Returns a page of DoNotInvite objects as { data, next_cursor }.
curl "https://valore.app/api/v1/do-not-invite?search=demo" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "dni_1",
      "email": "linus@example.com",
      "note": "Asked not to be invited",
      "created_at": "2026-10-17T19:00:00.000Z"
    }
  ],
  "next_cursor": null
}
POST/api/v1/do-not-invite

Add to the do-not-invite list

Up to 5,000 addresses per call. Invalid addresses are skipped; ones already listed are counted, not duplicated.

Body parameters
emails
string[]required
note
string
Why, e.g. asked by email.
Returns { data } with status 201.
curl -X POST "https://valore.app/api/v1/do-not-invite" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "emails": [
    "linus@example.com"
  ],
  "note": "Asked not to be invited"
}'
Response · 201
{
  "data": {
    "added": 1,
    "already_listed": 0
  }
}
DELETE/api/v1/do-not-invite/:id

Remove from the do-not-invite list

`id` is the entry id or the email address (URL-encoded). The address can be invited again.

Returns { data }.
curl -X DELETE "https://valore.app/api/v1/do-not-invite/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "dni_1",
    "removed": true
  }
}

Team

People with a role on the calendar: owner, admins and members.

GET/api/v1/team

List team members

Returns { data: Member[] }.
curl "https://valore.app/api/v1/team" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "mem_1",
      "user_id": "usr_88",
      "name": "Grace Hopper",
      "email": "grace@example.com",
      "username": "grace",
      "avatar_url": null,
      "role": "admin",
      "joined_at": "2026-09-28T17:00:00.000Z"
    }
  ]
}

Webhooks

Manage endpoints and inspect deliveries programmatically. See the Webhooks guide for payloads and signatures.

GET/api/v1/webhooks

List webhooks

Returns { data: Webhook[] }.
curl "https://valore.app/api/v1/webhooks" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "wh_1",
      "url": "https://example.com/webhooks/valore",
      "events": [
        "guest.registered",
        "guest.updated"
      ],
      "active": true,
      "last_status": 200,
      "last_error": null,
      "last_sent_at": "2026-10-03T21:14:11.000Z",
      "created_at": "2026-10-01T17:10:00.000Z"
    }
  ]
}
POST/api/v1/webhooks

Create a webhook

  • The response includes secret exactly once. Store it to verify signatures.
Body parameters
url
stringrequired
Public HTTPS endpoint.
events
string[]required
Event names to receive.
event.createdevent.updatedevent.publishedevent.canceledevent.deletedguest.registeredguest.updatedguest.checked_inorder.paidorder.refundedsubscriber.createdsubscriber.unsubscribedfeedback.submitted
Returns { data: Webhook } with status 201.
curl -X POST "https://valore.app/api/v1/webhooks" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://example.com/webhooks/valore",
  "events": [
    "guest.registered",
    "guest.updated"
  ]
}'
Response · 201
{
  "data": {
    "id": "wh_1",
    "url": "https://example.com/webhooks/valore",
    "events": [
      "guest.registered",
      "guest.updated"
    ],
    "active": true,
    "last_status": 200,
    "last_error": null,
    "last_sent_at": "2026-10-03T21:14:11.000Z",
    "created_at": "2026-10-01T17:10:00.000Z",
    "secret": "whsec_…"
  }
}
GET/api/v1/webhooks/:id

Retrieve a webhook

Returns { data: Webhook }.
curl "https://valore.app/api/v1/webhooks/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "wh_1",
    "url": "https://example.com/webhooks/valore",
    "events": [
      "guest.registered",
      "guest.updated"
    ],
    "active": true,
    "last_status": 200,
    "last_error": null,
    "last_sent_at": "2026-10-03T21:14:11.000Z",
    "created_at": "2026-10-01T17:10:00.000Z"
  }
}
PATCH/api/v1/webhooks/:id

Update a webhook

Body parameters
url
string
events
string[]
event.createdevent.updatedevent.publishedevent.canceledevent.deletedguest.registeredguest.updatedguest.checked_inorder.paidorder.refundedsubscriber.createdsubscriber.unsubscribedfeedback.submitted
active
boolean
Pause or resume.
rotate_secret
boolean
Issue a new secret (returned once).
Returns { data: Webhook }.
curl -X PATCH "https://valore.app/api/v1/webhooks/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "active": false
}'
Response · 200
{
  "data": {
    "id": "wh_1",
    "url": "https://example.com/webhooks/valore",
    "events": [
      "guest.registered",
      "guest.updated"
    ],
    "active": false,
    "last_status": 200,
    "last_error": null,
    "last_sent_at": "2026-10-03T21:14:11.000Z",
    "created_at": "2026-10-01T17:10:00.000Z"
  }
}
DELETE/api/v1/webhooks/:id

Delete a webhook

Returns { data }.
curl -X DELETE "https://valore.app/api/v1/webhooks/EVENT_OR_RESOURCE_ID" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "wh_1",
    "deleted": true
  }
}
POST/api/v1/webhooks/:id/test

Send a test ping

Returns { data }.
curl -X POST "https://valore.app/api/v1/webhooks/EVENT_OR_RESOURCE_ID/test" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "ok": true,
    "status": 200,
    "error": null
  }
}
GET/api/v1/webhooks/:id/deliveries

List deliveries

Query parameters
limit
integerdefault 25
Page size, 1–100.
cursor
string
The next_cursor from the previous page.
Returns a page of Delivery objects as { data, next_cursor }.
curl "https://valore.app/api/v1/webhooks/EVENT_OR_RESOURCE_ID/deliveries" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "whd_1",
      "webhook_id": "wh_1",
      "event": "guest.registered",
      "status": "succeeded",
      "attempts": 1,
      "response_status": 200,
      "error": null,
      "duration_ms": 212,
      "next_attempt_at": null,
      "delivered_at": "2026-10-03T21:14:11.000Z",
      "created_at": "2026-10-03T21:14:10.000Z",
      "payload": {
        "id": "whd_1",
        "type": "guest.registered",
        "created_at": "2026-10-03T21:14:10.000Z",
        "data": {
          "id": "gst_2c9d10",
          "…": "…"
        }
      }
    }
  ],
  "next_cursor": null
}
POST/api/v1/webhook-deliveries/:id/redeliver

Redeliver

  • Sends the same payload again with a fresh signature.
Returns { data: Delivery }.
curl -X POST "https://valore.app/api/v1/webhook-deliveries/EVENT_OR_RESOURCE_ID/redeliver" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "id": "whd_1",
    "webhook_id": "wh_1",
    "event": "guest.registered",
    "status": "succeeded",
    "attempts": 1,
    "response_status": 200,
    "error": null,
    "duration_ms": 212,
    "next_attempt_at": null,
    "delivered_at": "2026-10-03T21:14:11.000Z",
    "created_at": "2026-10-03T21:14:10.000Z",
    "payload": {
      "id": "whd_1",
      "type": "guest.registered",
      "created_at": "2026-10-03T21:14:10.000Z",
      "data": {
        "id": "gst_2c9d10",
        "…": "…"
      }
    }
  }
}

Vendors

The Bay Area event vendor directory (the same as valore.app/vendors): search by service, place and kind of event. Read-only and shared by every key.

GET/api/v1/vendors

Search vendors

Search the San Francisco Bay Area vendor directory: rentals, AV, photo booths, DJs, live music, entertainers, photo and video, caterers, food trucks, mobile bars, florists, decor, cakes, hair and makeup, officiants, emcees, auctioneers, team building, event staff and planners. Best match first.

  • Read-only and the same for every key: the directory isn't tied to your calendar.
  • Valore lists vendors but doesn't book them or vouch for them. Contact each vendor at its website.
  • Only the Bay Area is covered. Unmatched words return no results rather than everything.
Query parameters
q
string
What you need in plain words: service, place and occasion, e.g. "string quartet for a wedding in Marin" or "taco truck San Jose".
category
string
One of: rentals, av, photobooth, dj, music, entertainer, photo, catering, foodtruck, bar, florist, decor, cake, beauty, officiant, emcee, auctioneer, teambuilding, staffing, planner.
rentalsavphotoboothdjmusicentertainerphotocateringfoodtruckbarfloristdecorcakebeautyofficiantemceeauctioneerteambuildingstaffingplanner
region
string
One of: San Francisco, East Bay, Peninsula, South Bay, North Bay.
San FranciscoEast BayPeninsulaSouth BayNorth Bay
for
string
Kind of event: wedding, birthday, kids, corporate, fundraiser, holiday, backyard, shower, milestone. Narrows to the vendors that event usually needs when no service is named.
weddingbirthdaykidscorporatefundraiserholidaybackyardshowermilestone
limit
integerdefault 25
Max results, 1–100.
Returns { data: Vendor[] }.
curl "https://valore.app/api/v1/vendors?q=demo&category=rentals" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "name": "Garden Strings Music",
      "category": "music",
      "kind": "String quartet",
      "description": "String quartets, trios and duos for wedding ceremonies, cocktail hours and corporate events.",
      "areas": [
        "San Francisco",
        "Marin County",
        "Sonoma County"
      ],
      "regions": [
        "San Francisco",
        "North Bay"
      ],
      "good_for": [
        "wedding",
        "corporate"
      ],
      "website": "https://www.gardenstringsmusic.com/",
      "phone": null,
      "rating": {
        "source": "WeddingWire",
        "rating": 5,
        "review_count": 48,
        "url": "https://www.weddingwire.com/…",
        "checked_on": "2026-11-02"
      }
    }
  ],
  "total": 1,
  "interpreted_as": "Live music in the North Bay for a wedding",
  "checked_on": "2026-11-02"
}
GET/api/v1/events/:id/vendors

Vendor shortlist for an event

For one of your events: reads its city and kind (wedding, birthday, kids, corporate, fundraiser, holiday, backyard, shower, milestone) from its title, description or category, and returns the best few Bay Area vendors for each vendor type that kind of event usually needs.

  • covered: false with a reason for online events and events outside the San Francisco Bay Area; groups is then empty.
  • Set for when the event's kind is read wrong (event_type_from says how it was decided).
Query parameters
for
string
Override the kind of event when it can't be read from the event's title, description or category.
weddingbirthdaykidscorporatefundraiserholidaybackyardshowermilestone
categories
string
Comma-separated vendor types to include, e.g. catering,bar. One or more of: rentals, av, photobooth, dj, music, entertainer, photo, catering, foodtruck, bar, florist, decor, cake, beauty, officiant, emcee, auctioneer, teambuilding, staffing, planner.
per_category
integerdefault 3
Vendors per type, 1–5.
Returns { data: VendorPlan }.
curl "https://valore.app/api/v1/events/EVENT_OR_RESOURCE_ID/vendors?for=wedding&categories=demo" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": {
    "event_id": "evt_7f3ab1",
    "covered": true,
    "reason": null,
    "event_type": "wedding",
    "event_type_from": "title",
    "region": "North Bay",
    "summary": "14 vendor types for this event in the North Bay",
    "groups": [
      {
        "category": "music",
        "label": "Live music",
        "vendors": [
          {
            "name": "Garden Strings Music",
            "category": "music",
            "kind": "String quartet",
            "…": "…"
          }
        ]
      }
    ],
    "checked_on": "2026-11-02"
  }
}

Venues

The Bay Area event venue directory (the same as valore.app/venues): search by kind of place, area, kind of event and headcount. Read-only and shared by every key.

GET/api/v1/venues

Search venues

Search the San Francisco Bay Area venue directory: hotel ballrooms, wineries, estates and gardens, historic halls, museums, lofts, rooftops, waterfront spaces, private dining rooms, bars, breweries, meeting spaces, parks and activity venues. Best match first.

  • Read-only and the same for every key: the directory isn't tied to your calendar.
  • Valore lists venues but doesn't book them. Check availability and pricing with each venue at its website.
  • guests (or a headcount in q) keeps only venues that publish a capacity at least that large.
  • Only the Bay Area is covered. Unmatched words return no results rather than everything.
Query parameters
q
string
What you want in plain words: kind of place, area, occasion and headcount, e.g. "winery wedding in Sonoma for 150 guests" or "rooftop SF".
category
string
One of: hotel, winery, estate, historic, museum, loft, rooftop, waterfront, restaurant, bar, brewery, conference, outdoor, activity.
hotelwineryestatehistoricmuseumloftrooftopwaterfrontrestaurantbarbreweryconferenceoutdooractivity
region
string
One of: San Francisco, East Bay, Peninsula, South Bay, North Bay.
San FranciscoEast BayPeninsulaSouth BayNorth Bay
for
string
Kind of event: wedding, birthday, kids, corporate, fundraiser, holiday, backyard, shower, milestone. Narrows to the kinds of venue that event usually happens in when no kind is named.
weddingbirthdaykidscorporatefundraiserholidaybackyardshowermilestone
guests
integer
Headcount: only venues that state they hold at least this many.
limit
integerdefault 25
Max results, 1–100.
Returns { data: Venue[] }.
curl "https://valore.app/api/v1/venues?q=demo&category=hotel" \
  -H "Authorization: Bearer $VALORE_API_KEY"
Response · 200
{
  "data": [
    {
      "name": "Example Hill Winery",
      "category": "winery",
      "kind": "Vineyard estate",
      "description": "Family winery with a barrel room, a lawn above the vines and a terrace for weddings and private dinners.",
      "areas": [
        "Sonoma"
      ],
      "regions": [
        "North Bay"
      ],
      "address": "100 Example Rd, Sonoma, CA 95476",
      "capacity": {
        "seated": 180,
        "standing": 250,
        "max": 250
      },
      "good_for": [
        "wedding"
      ],
      "website": "https://example.com/events",
      "phone": "(707) 555-0100",
      "image_url": "https://valore.app/images/venues/example-hill-winery.webp",
      "image_is_illustration": false,
      "rating": {
        "source": "Yelp",
        "rating": 4.6,
        "review_count": 212,
        "url": "https://www.yelp.com/…",
        "checked_on": "2026-11-03"
      }
    }
  ],
  "total": 1,
  "interpreted_as": "Wineries in the North Bay for a wedding, 150+ guests",
  "checked_on": "2026-11-03"
}
Guides

Webhooks

Register an HTTPS endpoint in Settings → Developers (or via POST /webhooks) and pick the events you want. Valore POSTs a signed JSON body for each one. Respond with any 2xx within 8 seconds; do the real work asynchronously.

Events

TypeWhen
event.createdA new event is created on this calendar
event.updatedAn event’s details change
event.publishedA draft event goes live
event.canceledAn event is canceled
event.deletedAn event is permanently deleted
guest.registeredSomeone registers or requests to join
guest.updatedA guest’s status changes (approved, declined…)
guest.checked_inA guest is checked in at the door
order.paidA ticket order is paid
order.refundedAn order is refunded (fully or partially)
subscriber.createdSomeone subscribes to the calendar
subscriber.unsubscribedA subscriber opts out
feedback.submittedA guest leaves post-event feedback
pingYou pressed “Send test” or called the test endpoint

Delivery format

Guest, Order and Subscriber payloads use exactly the shapes returned by the REST API. The top-level id is the delivery id: retries reuse it, so store it to make your handler idempotent.

Example delivery
POST /your/endpoint
content-type: application/json
user-agent: Valore-Webhooks/1.0
x-valore-timestamp: 1790000000
x-valore-signature: 5f2b…c9   (hex HMAC-SHA256 of "<timestamp>.<raw body>")

{
  "id": "whd_01j9…",                   // delivery id: use it to de-duplicate retries
  "type": "guest.registered",
  "created_at": "2026-10-01T17:04:12.000Z",
  "data": { "id": "gst_…", "event_id": "evt_…", "name": "Ada Lovelace", "email": "ada@example.com", "status": "going", "…": "…" }
}

Verifying signatures

Each request carries x-valore-timestamp (Unix seconds) and x-valore-signature: the hex HMAC-SHA256 of `${timestamp}.${rawBody}` using the endpoint's signing secret. Verify against the raw body bytes, compare in constant time, and reject timestamps older than a few minutes. Rotating the secret from the dashboard invalidates the old one immediately.

import { createHmac, timingSafeEqual } from "node:crypto";

// Read the RAW request body (before JSON parsing) and pass the headers.
export function verifyValoreWebhook(rawBody, headers, secret = process.env.VALORE_WEBHOOK_SECRET) {
  const timestamp = headers["x-valore-timestamp"];
  const signature = headers["x-valore-signature"];
  if (!timestamp || !signature) return false;
  // Reject requests older than 5 minutes to prevent replays.
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(signature);
  return a.length === b.length && timingSafeEqual(a, b);
}

Retries and monitoring

  • A non-2xx response, a timeout (8s) or a connection error counts as a failure.
  • Failed deliveries are retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours (6 attempts in total), then marked failed.
  • Every attempt is logged. Inspect deliveries, see the exact payload and redeliver from the dashboard or with GET /webhooks/:id/deliveries.
  • Endpoints must be public HTTPS URLs. Localhost, private networks and URLs with credentials are rejected. Redirects are not followed.
  • Order of delivery isn't guaranteed across events; use the timestamps and ids in the payload rather than arrival order.

Valore speaks the Model Context Protocol over Streamable HTTP at https://valore.app/api/mcp. Connect Claude Code, Claude Desktop, Cursor or any MCP client with your API key and the assistant can list events, review guests, send invites and more, all scoped to the key's calendar. Read-only keys expose only read tools.

Claude Code
claude mcp add --transport http valore https://valore.app/api/mcp \
  --header "Authorization: Bearer vlr_YOUR_API_KEY"
search_public_eventsread

Search upcoming public events across all of Valore (not limited to your calendar). Matches the title, description, venue and tags; optionally filter by city, category, Valore Executive (high-end / investor / executive events) or AI-classified kinds.

list_eventsread

List events on your calendar (the calendar this API key belongs to), sorted by start time. Filter by status or a date range.

get_eventread

Retrieve one event on your calendar with its ticket types, live guest stats (going, pending, waitlist, checked in, revenue, page views) and night-before intros (setting, send time, how many guests answered and opted in, emails sent).

create_eventwrite

Create an event on your calendar. It's published immediately unless status is "draft". Dates are wall-clock times in `timezone` (or ISO with an offset). Use price_cents for a single paid ticket (omit for free).

update_eventsends email

Change fields on an event (send only what should change). Registered guests are emailed about time/location changes unless notify_guests is false. status "canceled" cancels the event and notifies guests (add refund_paid_guests: true to refund paid tickets); "published" publishes a draft.

list_guestsread

List an event's guests (registrations, invitees, waitlist). Filter by status, check-in state, or search by name/email.

update_guest_statussends email

Approve, decline, waitlist or otherwise change a guest's status (e.g. status "going" approves a pending guest). The guest is emailed unless notify is false. Approving a guest who owes payment keeps them pending until they pay.

check_in_guestwrite

Mark a confirmed (going) guest as arrived, by guest_id or by the ticket_token from their QR code. undo: true reverses a check-in.

check_invite_listread

Before send_invites: flag addresses on the do-not-invite list, opted out, bounced, unsubscribed, invalid or misspelled (with a suggested fix). Sends nothing; addresses with no issue are left out.

send_invitessends email

Email invitations to an event from the API key owner. People who are already registered are skipped. Up to 500 per call.

create_blastwrite

Draft an email blast. With event_id it goes to that event's guests (audience: guest statuses such as going, pending_approval, waitlist, checked_in, not_checked_in; default going). Without event_id it's a newsletter to your calendar's subscribers (audience: subscriber tags; empty = everyone). Nothing is sent until send_blast, unless scheduled_at is set.

send_blastsends email

Send a drafted blast now to its audience. Blasts that were already sent can't be sent again.

list_subscribersread

List people subscribed to your calendar (newest first). Filter by status, tag, or search by name/email.

add_subscriberswrite

Add people to your calendar's subscriber list (up to 500 per call), optionally tagging them. People who previously unsubscribed are left opted out.

get_event_insightsread

Analytics for one event: guest stats, registrations by day, page views and top traffic sources, guest sources, feedback ratings and email performance.

list_photosread

List an event's photo album (newest first), including hidden ones. featured = shown under "Event photos" on the page; the rest are "Community photos" shared by guests.

update_photowrite

Feature a photo in "Event photos" (featured: true) or move it to "Community photos" (false), hide or unhide it, or edit its caption. Photo ids come from list_photos.

list_do_not_inviteread

List addresses on the calendar's do-not-invite list (never sent invites from any event on it).

add_to_do_not_invitewrite

Add addresses to the calendar's do-not-invite list so no event on it ever invites them (they can still RSVP to public events).

export_attendeesread

List attendees across several or all of the calendar's events, each row with its event. Filter by event ids or a start-date range; page with cursor.

refund_ordersends email

Refund a paid ticket order through Stripe: in full (omit amount_cents) or partially. This moves real money. Order ids come from the orders on get_event or the REST orders list.

list_tracking_linksread

List an event's tracking links (short share links per channel) with clicks, visitors, registrations, tickets and revenue for each, to see which channel brings guests.

create_tracking_linkwrite

Create a short share link for one channel (newsletter, Instagram, a partner) so registrations through it are counted separately. Optional UTM tags, a coupon code applied at checkout, and a preselected ticket type.

list_staff_linksread

List an event's door-staff check-in links (no login needed to use them), whether each is active, and how many guests each checked in.

create_staff_linkwrite

Create a check-in link for door staff or volunteers: anyone with the URL can scan tickets and check guests in without a Valore account, until it's revoked.

list_pollsread

List an event's polls and "Find a time" date polls with live yes / maybe / no counts per option.

create_pollwrite

Add a poll to an event page (kind "poll", text options) or a "Find a time" date poll (kind "date", options with starts_at and ends_at as wall-clock "YYYY-MM-DDTHH:mm" in the event timezone). Guests vote on the page.

list_commentsread

Read an event's discussion: comments with replies, reactions, and whether each is from a host, pinned or hidden.

post_commentsends email

Post a comment (or a reply with parent_id) in an event's discussion as the host. Guests following the discussion are notified.

list_peopleread

Search the calendar's people (subscribers, past guests, imports) with filters: tags, attended/registered at least N events, spent at least, city, active in the last N days, specific events, SMS opt-in, or a saved segment. Returns contacts with tags, event counts and spend, plus the total.

get_personread

Full CRM profile for one person: details, stats, registrations and orders, messages sent, the activity timeline (notes, check-ins) and segments. Person ids come from list_people.

add_person_notewrite

Add a note to a person's CRM timeline (visible to the calendar's team).

tag_peoplewrite

Add or remove tags on people, chosen by ids (from list_people) or by filters. Tags drive segments and campaign audiences.

list_segmentsread

List saved segments (named people filters) with their current size. Use a segment id in list_people or as a campaign audience.

create_segmentwrite

Save a named people filter (e.g. "Regulars": attended at least 3 events). Segments update automatically as people match.

create_campaignsends email

Draft an email or text campaign to a CRM audience: all, tags, a segment, specific people, an event's guests (by status) or filters. Merge fields {first_name}, {event_title}, {event_link}. Saved as a draft; preview_campaign_audience shows who'd get it, and send_blast sends it.

preview_campaign_audienceread

Count who a campaign would reach (and who'd be excluded, e.g. unsubscribed or no SMS consent) before drafting or sending. Sends nothing.

list_dealsread

List the sponsor / partner deal pipeline (stages: lead, contacted, negotiating, committed, won, lost) with values and totals per stage.

create_dealwrite

Add a sponsor or partner deal to the pipeline, optionally tied to an event, with a value in cents and a next-step date.

update_dealwrite

Update a deal or move it to another stage (lead, contacted, negotiating, committed, won, lost). Deal ids come from list_deals.

list_membership_tiersread

List the calendar's membership tiers (free, one-time, monthly or yearly) with prices and whether they need approval.

list_membersread

List the calendar's members with their tier and status (pending approval, active, past due, canceled). Filter by status or tier.

approve_membersends email

Approve a pending membership request (from list_members with status pending). The member is emailed.

find_vendorsread

Find event vendors in the San Francisco Bay Area (only area covered): DJs, caterers, food trucks, florists, string quartets, rentals, photographers, entertainers, emcees, auctioneers, team building, event staff, planners and more. Pass the request as plain text in `q`. Returns each vendor's own website, phone and any third-party rating. Valore doesn't book vendors.

plan_event_vendorsread

For one event on this calendar: a Bay Area vendor shortlist per vendor type that kind of event needs (a wedding: planner, florist, photographer, caterer, music, officiant…), read from the event's city, title and category. Say how the event was read (event_type_from) and offer to change it with `for`. Valore doesn't book vendors or know prices.

find_venuesread

Find event venues in the San Francisco Bay Area (only area covered): ballrooms, wineries, estates, historic halls, museums, lofts, rooftops, waterfront, private dining, bars, breweries, meeting spaces and activity venues. Pass the request as plain text in `q` (a headcount like "for 150 guests" filters by stated capacity). Returns each venue's events page, phone, capacity and any third-party rating. Valore doesn't book venues.

Step-by-step setup for each client lives in Settings → Developers → MCP.

A machine-readable OpenAPI 3.1 document is published at /api/v1/openapi.json. Import it into Postman, Insomnia or an SDK generator, or point a code assistant at it.

2026-11-03
  • Venues: GET /venues searches the San Francisco Bay Area venue directory (valore.app/venues) by plain-text request, kind of venue, region, kind of event and headcount (guests), with each venue's events page, address, stated capacity, phone and any third-party rating. MCP: find_venues.
2026-11-02
  • CRM: /people (search with filters, profile with timeline, create, update, notes, bulk tag / unsubscribe / block, duplicates and merge), /segments, /campaigns (email and text to any audience, with audience preview and test sends) and /deals (the sponsor pipeline).
  • Memberships: /membership-tiers and /members (list, approve, cancel).
  • MCP: list_people, get_person, add_person_note, tag_people, list_segments, create_segment, create_campaign, preview_campaign_audience, list_deals, create_deal, update_deal, list_membership_tiers, list_members and approve_member.
  • Vendors: GET /vendors searches the San Francisco Bay Area vendor directory (valore.app/vendors) by plain-text request, category, region and kind of event, with each vendor's website, phone and any third-party rating. MCP: find_vendors. GET /events/:id/vendors (MCP: plan_event_vendors) builds a shortlist per vendor type for one of your events from its city and kind.
  • Events: imports refuse pages that publish a recurring series as one event spanning months or years, so imported events (external_url set) have real dates.
  • New resources: tracking links, staff check-in links, polls (including "Find a time" date polls) and the event discussion.
  • Orders: POST /orders/:id/refund refunds in full or partially. Events: refund_paid_guests on PATCH /events/:id with status: "canceled" refunds every paid guest; GET /events/:id/insights returns event analytics.
  • Newsletters: GET and POST /newsletters list and create emails to the calendar's subscribers (send them with POST /blasts/:id/send).
  • MCP: refund_order, list_tracking_links, create_tracking_link, list_staff_links, create_staff_link, list_polls, create_poll, list_comments and post_comment; update_event takes refund_paid_guests.
  • New resources: event photos (list, feature, hide, caption, delete) and the calendar's do-not-invite list.
  • POST /events/:id/invites/check flags addresses that shouldn't be invited (do-not-invite, opted out, bounced, unsubscribed, invalid or misspelled) before you send.
  • MCP: list_photos, update_photo, list_do_not_invite, add_to_do_not_invite and check_invite_list. The server also answers at /mcp.
2026-10-17
  • GET /attendees: every guest across the calendar's events in one export (MCP export_attendees).
  • Invitations skip anyone on the calendar's do-not-invite list, opted out of the host's invites, blocked, or whose address hard-bounced or complained; the send response counts them in excluded.
2026-10-10
  • Night-before intros: events take intros_enabled (true, false or null for automatic) and return intros_setting; event insights add intros counts (answered, opted in, sent). Guests' answers stay private.
2026-10-07
  • Events return listing_links: the same event's pages elsewhere (Partiful, Luma, Eventbrite…), shown as "Also on" links.
2026-10-04
  • Coupons: fixed_price_cents makes the ticket cost a set price (0 is allowed). A code takes one of percent_off, amount_off_cents or fixed_price_cents.
  • Invitations: people can be { email, name, phone }, and send_text: true also texts the RSVP link where SMS is set up (response adds texted and texts_skipped).
2026-09-30
  • GET /brand-themes lists the calendar's brand themes; events return brand_theme_id and apply one with theme.brand.
2026-09-28
  • New resources: hosts, ticket types, coupons, registration questions, orders, feedback, blasts, team, webhooks and /me.
  • Events: publish, duplicate and delete. Guests: calendar-wide search, detail edits and removal. Subscribers: retrieve, update, delete and bulk import.
  • Read-only API keys, per-key rate limits with X-RateLimit-* headers, and X-Request-Id on every response.
  • Webhooks: delivery log with automatic retries and redelivery; new events event.published, event.deleted, order.paid, order.refunded, subscriber.created, subscriber.unsubscribed.
  • OpenAPI 3.1 document at /api/v1/openapi.json.
2026-06-01
  • Initial public API: calendar, events, guests, invitations and subscribers. Webhooks with HMAC-SHA256 signatures. MCP server.
Questions or a missing endpoint? Tell the Valore Agent (bottom right) and it files a request with the team, or email developers@valore.app.