curl --request POST \
--url https://attend.hackclub.com/api/v1/events/{event_id}/participants \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"email": "[email protected]",
"first_name": "<string>",
"last_name": "<string>",
"date_of_birth": "2009-04-02",
"phone": "<string>",
"country": "<string>",
"address_line_1": "<string>",
"address_line_2": "<string>",
"city": "<string>",
"state": "<string>",
"postal_code": "<string>"
}
'import requests
url = "https://attend.hackclub.com/api/v1/events/{event_id}/participants"
payload = {
"email": "[email protected]",
"first_name": "<string>",
"last_name": "<string>",
"date_of_birth": "2009-04-02",
"phone": "<string>",
"country": "<string>",
"address_line_1": "<string>",
"address_line_2": "<string>",
"city": "<string>",
"state": "<string>",
"postal_code": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
email: '[email protected]',
first_name: '<string>',
last_name: '<string>',
date_of_birth: '2009-04-02',
phone: '<string>',
country: '<string>',
address_line_1: '<string>',
address_line_2: '<string>',
city: '<string>',
state: '<string>',
postal_code: '<string>'
})
};
fetch('https://attend.hackclub.com/api/v1/events/{event_id}/participants', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://attend.hackclub.com/api/v1/events/{event_id}/participants",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'email' => '[email protected]',
'first_name' => '<string>',
'last_name' => '<string>',
'date_of_birth' => '2009-04-02',
'phone' => '<string>',
'country' => '<string>',
'address_line_1' => '<string>',
'address_line_2' => '<string>',
'city' => '<string>',
'state' => '<string>',
'postal_code' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://attend.hackclub.com/api/v1/events/{event_id}/participants"
payload := strings.NewReader("{\n \"email\": \"[email protected]\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"date_of_birth\": \"2009-04-02\",\n \"phone\": \"<string>\",\n \"country\": \"<string>\",\n \"address_line_1\": \"<string>\",\n \"address_line_2\": \"<string>\",\n \"city\": \"<string>\",\n \"state\": \"<string>\",\n \"postal_code\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://attend.hackclub.com/api/v1/events/{event_id}/participants")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"email\": \"[email protected]\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"date_of_birth\": \"2009-04-02\",\n \"phone\": \"<string>\",\n \"country\": \"<string>\",\n \"address_line_1\": \"<string>\",\n \"address_line_2\": \"<string>\",\n \"city\": \"<string>\",\n \"state\": \"<string>\",\n \"postal_code\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://attend.hackclub.com/api/v1/events/{event_id}/participants")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"email\": \"[email protected]\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"date_of_birth\": \"2009-04-02\",\n \"phone\": \"<string>\",\n \"country\": \"<string>\",\n \"address_line_1\": \"<string>\",\n \"address_line_2\": \"<string>\",\n \"city\": \"<string>\",\n \"state\": \"<string>\",\n \"postal_code\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"held": false,
"message": "Invitation sent to [email protected]",
"event": "My Event",
"participant_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"participant_event_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"status": "invited"
}{
"error": "Unauthorized"
}{
"error": "Unauthorized"
}{
"error": "Unauthorized"
}{
"success": false,
"error": "This email is already registered for this event"
}{
"success": false,
"error": "This email is already registered for this event"
}Invite a participant
Send an event invitation email and put the person on the roster.
The registration is created with status invited — the same state a CSV import leaves people in. They move to in_progress on their own when they first open the onboarding wizard. first_name/last_name are optional; when omitted the participant is created with placeholder legal names that are replaced from their account on first sign-in.
date_of_birth, phone, country and the address fields are optional too. Everything sent is stored on the participant; the name, birthday, phone and country also prefill the Hack Club Auth signup form when they open the invitation and don’t have an account yet. If the email already belongs to someone Attend knows (from another event), only the fields they have no value for are filled in; nothing they entered is overwritten. The address counts as one value: if any part of one is on file, none of the address fields sent are written.
While the event is holding onboarding invitations (modules.onboarding_invites_held), the invitation is recorded but not emailed: it goes out when the event’s held invitations are released from the dashboard. The response says which happened. A held invitation still creates the invited registration, and the wizard stays shut to them until it is released.
curl --request POST \
--url https://attend.hackclub.com/api/v1/events/{event_id}/participants \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"email": "[email protected]",
"first_name": "<string>",
"last_name": "<string>",
"date_of_birth": "2009-04-02",
"phone": "<string>",
"country": "<string>",
"address_line_1": "<string>",
"address_line_2": "<string>",
"city": "<string>",
"state": "<string>",
"postal_code": "<string>"
}
'import requests
url = "https://attend.hackclub.com/api/v1/events/{event_id}/participants"
payload = {
"email": "[email protected]",
"first_name": "<string>",
"last_name": "<string>",
"date_of_birth": "2009-04-02",
"phone": "<string>",
"country": "<string>",
"address_line_1": "<string>",
"address_line_2": "<string>",
"city": "<string>",
"state": "<string>",
"postal_code": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
email: '[email protected]',
first_name: '<string>',
last_name: '<string>',
date_of_birth: '2009-04-02',
phone: '<string>',
country: '<string>',
address_line_1: '<string>',
address_line_2: '<string>',
city: '<string>',
state: '<string>',
postal_code: '<string>'
})
};
fetch('https://attend.hackclub.com/api/v1/events/{event_id}/participants', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://attend.hackclub.com/api/v1/events/{event_id}/participants",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'email' => '[email protected]',
'first_name' => '<string>',
'last_name' => '<string>',
'date_of_birth' => '2009-04-02',
'phone' => '<string>',
'country' => '<string>',
'address_line_1' => '<string>',
'address_line_2' => '<string>',
'city' => '<string>',
'state' => '<string>',
'postal_code' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://attend.hackclub.com/api/v1/events/{event_id}/participants"
payload := strings.NewReader("{\n \"email\": \"[email protected]\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"date_of_birth\": \"2009-04-02\",\n \"phone\": \"<string>\",\n \"country\": \"<string>\",\n \"address_line_1\": \"<string>\",\n \"address_line_2\": \"<string>\",\n \"city\": \"<string>\",\n \"state\": \"<string>\",\n \"postal_code\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://attend.hackclub.com/api/v1/events/{event_id}/participants")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"email\": \"[email protected]\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"date_of_birth\": \"2009-04-02\",\n \"phone\": \"<string>\",\n \"country\": \"<string>\",\n \"address_line_1\": \"<string>\",\n \"address_line_2\": \"<string>\",\n \"city\": \"<string>\",\n \"state\": \"<string>\",\n \"postal_code\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://attend.hackclub.com/api/v1/events/{event_id}/participants")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"email\": \"[email protected]\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"date_of_birth\": \"2009-04-02\",\n \"phone\": \"<string>\",\n \"country\": \"<string>\",\n \"address_line_1\": \"<string>\",\n \"address_line_2\": \"<string>\",\n \"city\": \"<string>\",\n \"state\": \"<string>\",\n \"postal_code\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"held": false,
"message": "Invitation sent to [email protected]",
"event": "My Event",
"participant_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"participant_event_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"status": "invited"
}{
"error": "Unauthorized"
}{
"error": "Unauthorized"
}{
"error": "Unauthorized"
}{
"success": false,
"error": "This email is already registered for this event"
}{
"success": false,
"error": "This email is already registered for this event"
}Authorizations
Mobile token, global API token, series API key, or event API key. See Authentication above for which endpoints each one reaches.
Path Parameters
Event id or slug.
Body
Can't be in the future.
"2009-04-02"
E.164 format, e.g. +12025550100
ISO 3166-1 alpha-2 code (e.g. US) or the country's English name.
Response
Invitation enqueued, or recorded as held.
true
True when the event is holding onboarding invitations and this one was recorded without an email.
false
"Invitation sent to [email protected]"
"My Event"
The person created or matched for this invitation.
Their registration for this event.
Registration status, invited on creation.
"invited"
Was this page helpful?