Available with any of the following subscriptions:
✓ Ultimate
Use this endpoint to create a new event in Band Pencil. It supports single-day and multi-day events, optional start/end times, client and location payloads, and helpful metadata (notes, timings, equipment, etc.).
You will need to contact support to have the API enabled for your account.
Method & URL: POST https://management.bandpencil.com/api/v1/public/events
Content type: application/json
Auth: X-API-Key: (plain text)
Idempotency (recommended): Idempotency-Key:
Success: 201 Created with the new event_id and resource_url
Duplicate (with same Idempotency-Key): 200 OK (“Duplicate suppressed”)
Generate keys in Band Pencil → Settings → API. We will automatically assign your API key a unique name. Copy the key somewhere secure alongside the unique name, you won’t be able to view the API key again. You’ll see the key name in audit logs so you know which integration created what.
Send the following headers with every request:
Content-Type: application/json X-API-Key: Idempotency-Key: # optional but recommended X-API-Key is required. If missing or invalid you’ll receive 401/403.
Idempotency-Key prevents accidental duplicates (e.g., retries). If a request with the same key for the same account was already processed, the API returns 200 OK with "Duplicate suppressed" instead of creating another event.
Send a JSON object. Required fields are name and date. Everything else is optional unless your use-case dictates otherwise (see multi-day rules).
| Field | Type | Required | Rules & Notes |
|---|---|---|---|
name |
string | Yes | Event title, e.g., “Wedding – Smiths”. |
date |
date (YYYY-MM-DD) | Yes | Event start date. |
status |
string | No | Must be one of: Confirmed, Awaiting Confirmation, Pending Members, Pending Confirmation, Offer Accepted, Offer Made, Enquiry, Cancelled, Withdrawn, Not Won.If missing or invalid, defaults to Enquiry. |
multiple_days |
boolean | No | If true, you must send date_end. |
date_end |
date (YYYY-MM-DD) | Conditionally | Required when multiple_days is true. Must be on/after date. Ignored when multiple_days is false. |
time_start |
time (e.g., 18:00) |
No | 24-hour time; many common formats are accepted and normalised to HH:MM. |
time_end |
time (e.g., 23:00) |
No | If both start & end are omitted or 00:00, the event is treated as all-day. |
referral |
string | No | Will be created/re-used under Referral. |
location |
object | No | See Location object. |
client |
object | No | See Client object (recommended to attach a client). |
private_notes |
string | No | Stored privately; new lines are preserved. |
description |
string | No | Visible description/notes; new lines are preserved. |
timings_breakdown |
string | No | Free-form timings; new lines preserved. |
setup_breakdown |
string | No | Free-form tech/kit notes; new lines preserved. |
food_provided |
string | No | e.g., “Hot meal for 4”. |
noise_limit |
string | No | e.g., “92 dB”. |
number_of_guests |
string | No | Free-text or number. |
mileage |
string | No | Free-text or number. |
green_room |
string | No | e.g., “Room at the back of barn”. |
performance_room |
string | No | e.g., “Great Barn”. |
| Field | Type | Required | Notes |
|---|---|---|---|
name |
string | No | If provided, the API will re-use an exact match or create a new location. |
address |
string | No | New lines preserved; stored securely. |
The API attempts to re-use an existing location by location name for your account. If not found, it creates it and links it to the event.
| Field | Type | Required | Notes |
|---|---|---|---|
name |
string | No | Recommended. |
email |
string | No | Strongly recommended - used to match existing clients. |
phone |
string | No | |
company |
string | No |
The API de-duplicates by email address within your account. If a client with the same email exists, it re-uses that client; otherwise it creates a new one and links it.
curl -X POST "https://management.bandpencil.com/api/v1/public/events" \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY_HERE" \
-H "Idempotency-Key: 3f6f3b6e-3a5c-4c7c-9c9f-8a0c1c5e2c1a" \
-d '{
"name": "Wedding – Smiths",
"date": "2025-11-20",
"status": "Enquiry",
"time_start": "18:00",
"time_end": "23:00",
"multiple_days": false,
"referral": "Google",
"location": { "name": "Healey Barn", "address": "Riding Mill, Northumberland, NE44 6BN" },
"client": { "name": "John Smith", "email": "john.smith@example.com", "phone": "07123456789", "company": "Client Company" },
"private_notes": "Client prefers acoustic set.\nPlease park in staff car park.",
"description": "Evening wedding reception. Sound limiter present.",
"timings_breakdown": "Arrival 17:00\nSoundcheck 17:30\nFirst set 19:00–20:00\nSecond set 21:00–22:00",
"setup_breakdown": "2x powered speakers, 1x sub, 4x mics, 2x DI boxes.",
"food_provided": "Hot meal for 4",
"noise_limit": "92 dB",
"number_of_guests": "120",
"mileage": "18",
"green_room": "Yes",
"performance_room": "Great Barn"
}'
$client = new \GuzzleHttp\Client(['base_uri' => 'https://management.bandpencil.com']);
$res = $client->post('/api/v1/public/events', [
'headers' => [
'Content-Type' => 'application/json',
'X-API-Key' => $_ENV['BAND_PENCIL_API_KEY'],
'Idempotency-Key' => bin2hex(random_bytes(16)),
],
'json' => [
'name' => 'Charity Ball',
'status' => 'Enquiry',
'date' => '2026-05-18',
'multiple_days' => true,
'date_end' => '2026-05-19',
'timings_breakdown' => "Doors 18:30\nBand 20:00–22:00"
],
]);
$body = json_decode($res->getBody()->getContents(), true);
{
"status": "Success",
"message": "Event created",
"event_id": "e12345678",
"resource_url": "https://management.bandpencil.com/api/v1/events/e12345678",
"created_at": "2025-10-16T13:35:12Z",
"idempotency_key": "3f6f3b6e-3a5c-4c7c-9c9f-8a0c1c5e2c1a",
"version": "1.0"
}
{ "status": "Success", "message": "Duplicate suppressed", "version": "1.0" }
| HTTP | status |
Meaning / When you’ll see it |
|---|---|---|
| 400 | BadRequest |
Invalid or non-JSON request body. |
| 401 | AuthError |
Missing API key. |
| 403 | AuthError |
Invalid/inactive API key. |
| 403 | Limit |
A trial/basic limit was hit (specific scenario). |
| 422 | MissingFields |
name or date missing, or date_end missing when multiple_days=true. |
| 422 | ValidationError |
date_end is before date. |
| 422 | NotAllowed |
Your plan does not include API access. |
| 422 | OverLimit |
You’ve exceeded your plan’s event limit. |
| 500 | Failure |
Server/database/internal error. Retry with the same Idempotency-Key if you’re unsure whether the first attempt succeeded. |
Dates: Common inputs are accepted and normalised to YYYY-MM-DD.
Times: Common formats are accepted and normalised to HH:MM (24-hour).
If both time_start and time_end are omitted or resolve to 00:00, the event is treated as all-day.
Text fields: New lines are preserved. HTML is escaped (so paste plain text rather than HTML).
Location: If a location with the same name exists, it’s re-used; otherwise it’s created.
Client: Matched by email within your account; created if not found.
Referral: Re-used or created by exact match.
Use a unique key per logical create (e.g., a UUID).
On network timeouts, retry with the same Idempotency-Key to avoid duplicates.
If you intentionally want to create a new event, use a new Idempotency-Key.
422 MissingFields / ValidationError: Check name, date, and (if multiple_days=true) a valid date_end that’s not before date.
Times being ignored / all-day events: Ensure you’re using time_start and time_end (not time_start/time_end), and they parse to valid times.
403/422 plan or limit errors: Upgrade to Ultimate for API access and ensure your account hasn’t exceeded its account limits.
200 “Duplicate suppressed” unexpectedly: You likely reused an Idempotency-Key. Generate a fresh one for new creates.