studioHYPE API
Push leads and enrollment status into a studio's studioHYPE account from any system: your registration software, a website builder, or Zapier.
Authentication
Each studio has an account key, in Settings → Leads → API, and one key per connection in Settings → Leads → Integrations. Either works on every endpoint. Send it on every request:
Authorization: Bearer YOUR_API_KEY
Requests and responses are JSON (Content-Type: application/json). Form-encoded bodies work too. Check a key with GET https://studiohype.com/api/v1/me.
Add a lead
POST https://studiohype.com/api/v1/leads creates an inquiry. The family is matched by email or phone (or created), so you can send every inquiry without checking first. The studio gets a notification.
curl https://studiohype.com/api/v1/leads \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"first_name": "Jen",
"last_name": "Thompson",
"email": "[email protected]",
"phone": "555-123-4567",
"student_first_name": "Maya",
"student_last_name": "Thompson",
"student_birthdate": "2019-04-22",
"program": "Ballet",
"source": "website_form",
"message": "Looking for a Saturday class",
"external_id": "inq_4821",
"external_source": "my-site",
"tags": ["Fall open house"]
}'
first_name, last_name or nameemail, phonestudent_first_name, student_last_name or student_namestudent_birthdateYYYY-MM-DD. If your system only has an age, send student_age instead.program or program_idlocation or location_idsourcewebsite_form, phone, walk_in, referral, facebook, instagram, google, event, email, returning, import, api, other. Anything else is kept as the source detail. Defaults to api.source_detail, messagecampaignfall-registration-2026) or id. The lead is credited to that campaign, goes to its follow-up owner if assigned_to isn't set, and gets its reply-by date unless you send follow_up_on. Unknown codes are ignored.link/go/, also passed to your pages as sh=). The lead is credited to that campaign and to the post, email, or flyer the link was made for. Codes from other studios are ignored.stagenew, contacted, trial_scheduled, …). Defaults to the first stage.assigned_tofollow_up_onYYYY-MM-DD. Defaults to today.tagscustom_fields{"shirt_size": "Youth M", "school": "Lincoln Elementary"}. Keys are listed in Settings → Leads → Custom fields. Values that don't fit a field come back in warnings; the rest still saves.external_id, external_sourceReturns 201 with the lead (200 with "created": false when external_id matched an existing one).
Enrollment status
POST https://studiohype.com/api/v1/enrollments tells studioHYPE a family enrolled, dropped, or joined a waitlist. When a family enrolls, their open and nurturing inquiries for that program close automatically, so they stop getting follow-up.
{
"email": "[email protected]",
"student_first_name": "Maya",
"program": "Ballet",
"status": "enrolled"
}
statusenrolled (or active), dropped (or withdrawn, inactive), waitlist, interested.contact_id, or family_external_id + external_source, or email / phone. With create_if_missing (default true) and a name, an unknown family is added.program / program_idstudent_nameReturns the family and leads_closed, the number of inquiries it closed.
Add or update a family
POST https://studiohype.com/api/v1/contacts takes the same family and student fields as /app/leads (plus address, city, state, postal_code, guardian2_first_name, guardian2_last_name, guardian2_email, guardian2_phone) without creating an inquiry. Existing families only have blank details filled in.
Programs, locations, stages
GET https://studiohype.com/api/v1/programs, GET https://studiohype.com/api/v1/locations, and GET https://studiohype.com/api/v1/stages list the names and ids the other endpoints accept.
Reading leads
GET https://studiohype.com/api/v1/leads?since=2026-09-01T00:00:00Z&limit=50 lists recent leads, newest first (max 100). For the next page, pass before = the next_before value from the last response. GET https://studiohype.com/api/v1/leads/{id} returns one. Each includes status (open, enrolled, lost) and its stage.
Errors and limits
Errors return a status code and {"error": "code", "message": "…", "fields": {…}}: 400 bad JSON, 401 bad key, 404 not found, 422 invalid fields, 429 over the limit of 120 requests per minute. The studio can see recent requests and errors in their API settings.
Zapier
No code needed: add a Webhooks by Zapier → POST action, set the URL to an endpoint above, choose JSON, add the Authorization header, and map your trigger's fields. For Jackrabbit, Studio Pro, and other studio software there's an easier way: the connect endpoints below, which take the trigger's fields as they are.
Connected software
A studio sets up a connection in Settings → Leads → Integrations (Jackrabbit, Studio Pro, another tool via Zapier, or a named key for your code; a direct Jackrabbit connection reads Jackrabbit's API itself and needs none of this). A connection has its own key, and its key opens every endpoint above. It also opens the connect endpoints, which take a platform's raw trigger payload and work out the fields:
POST https://studiohype.com/api/v1/connect/{event} events: lead, family, student, enrolled, dropped, inactive, waitlist, unwaitlist, updated
Send whatever the trigger has (in Zapier, leave the POST action's Data empty and every field comes through). Field names are matched by meaning (ContactFirstName, parent_email, Student 1 DOB, ClassName, …); the studio sees anything that wasn't recognized and confirms what it means, with AI's help, and the event is applied once it can be placed. Class names are matched to the studio's programs the same way.
leadfamilystudentenrolleddroppedinactivewaitlistunwaitlistupdatedThe response says what happened: {"ok": true, "event_id": 812, "outcome": "lead_created", "message": "Added Jen Thompson as a lead.", "lead": {"id": 41, "url": "…"}, "unrecognized_fields": ["School Name"]}. Outcomes include lead_created, lead_updated, family_created, family_updated, student_added, enrolled, left, waitlisted, interested, no_change, needs_mapping (kept, waiting for the studio to confirm a field), needs_program (kept, waiting for a class to get its program), and skipped. A paused connection answers 403 paused; retry later. Sending an event twice is safe.