---
title: "Create a new signup"
method: POST
path: "/signups"
tags: ["Signups"]
---

# Create a new signup

`POST /signups`

## Request

- Base URL: `https://thesignup.app/api/v1`
- URL: `https://thesignup.app/api/v1/signups`
- Auth: HTTP bearer

Subject to the per-org daily ceiling (50 signups created per day, regardless of tier). Pass an `Idempotency-Key` header to make retries safe.

## Headers

- `Idempotency-Key` string: Opaque client-supplied key, ≤ 200 chars. Same key + same body within 24h returns the original response. Same key + different body returns 422.

## Request body

- CreateSignupRequest
  - `title` string, required
  - `description` string
  - `location` string
  - `eventDate` string, required: ISO-8601 datetime. Either UTC (`...Z`) / offset-bearing, OR a naive local string (`2026-09-15T17:00`) — naive form requires `timezone` to also be set; the server then interprets the string as wall-clock time in that zone.
  - `signupCloseDate` string: ISO-8601 datetime, same rules as eventDate. Defaults to never (signups stay open until the event).
  - `timezone` string: IANA timezone name (e.g. `America/Los_Angeles`). When provided, naive `eventDate`/`signupCloseDate`/slot times are parsed against this zone, and the value is stored on the signup so display surfaces can render the organizer's wall-clock intent.
  - `maxParticipants` integer
  - `requiresPhone` boolean: Default false.
  - `isPrivate` boolean: Default false.
  - `eventWideCustomField` object
    - `name` string, required
    - `required` boolean, required
    - `type` 'short' | 'long', required

## Response `201`

Signup created

- SignupDetail
  - `id` string, uuid, required
  - `organizationId` string, required
  - `slug` string, required
  - `title` string, required
  - `status` 'draft' | 'published' | 'closed', required
  - `eventDate` string, date-time, required: ISO-8601 UTC.
  - `signupCloseDate` string, date-time, nullable, required: ISO-8601 UTC. Null = signups never close until the event.
  - `location` string, nullable, required
  - `isPrivate` boolean, required
  - `createdAt` string, date-time, required
  - `updatedAt` string, date-time, required
  - `description` string, nullable, required
  - `maxParticipants` integer, nullable, required: Cap on total participants. Null only on a plan with no participant ceiling (uncapped); elsewhere the cap is stored as the plan ceiling.
  - `commitmentRequired` boolean, required: When true, a participant must claim a slot or an item to sign up — attending without committing to anything is not offered.
  - `requiresPhone` boolean, required
  - `timezone` string, required: IANA timezone the organizer attached to this signup. Display surfaces should prefer this over the viewer's local zone when rendering eventDate / slot times.
  - `eventWideCustomField` object, nullable, required: Optional one-off field shown on every signup form.
    - `name` string, required
    - `required` boolean, required
    - `type` 'short' | 'long', required
  - `days` Day[], required: Every day of the signup in date order, cancelled ones included. Same shape as `GET /signups/{id}/days`.
    - `id` string, uuid, required
    - `eventId` string, uuid, required
    - `date` string, required: The calendar date, `YYYY-MM-DD`, in the signup's timezone.
    - `seriesId` string, uuid, nullable, required: The Slot Series that generated this day, or null for a day added by hand or an ordinary signup's day.
    - `cancelledAt` string, date-time, nullable, required: When the day was called off, or null. A cancelled day keeps its slots, items and registrations. A repeating schedule's date is cancelled through its Shifts instead and keeps null here; read `noLiveTime`.
    - `noLiveTime` boolean, required: True when the day had times and none of them is live any more — participants are not offered it, exactly as a cancelled day.
    - `question` object, nullable, required: The Day Question asked once per day of whoever signs up for anything that day: the day's own, else the repeating schedule's default. Null when none.
      - `label` string, required
      - `placeholder` string: Example answer, shown as a hint in the answer box. Absent when none was given.
      - `required` boolean, required
    - `questionSource` 'own' | 'series' | 'null', nullable, required: Whose `question` it is: the day's own, or the schedule's default it inherits. Null when there is no question.
    - `isPast` boolean, required: Whether the date is before today in the signup's timezone.

## Other responses

- `401`: Unauthenticated — credentials missing, malformed, invalid, or revoked
- `409`: Not found
- `422`: Validation failed — request body / query / path is structurally wrong
- `429`: Rate limited or daily ceiling exceeded (50 signups/day/org regardless of tier)
- `500`: Internal server error

---

[API](https://skmtc.dev/thesignup/apis/thesignup-api.md) · [All operations](https://skmtc.dev/thesignup/apis/thesignup-api/llms.txt) · [OpenAPI document](https://skmtc.dev/thesignup/apis/thesignup-api/revisions/c6da7cf92172?raw)
