Presently API Documentation
Overview
Presently provides a RESTful API for programmatic access to your studio data. The API uses Laravel Sanctum for authentication via personal access tokens.
Authentication
Creating an API Token
- Log in to your Presently tenant admin panel
- Navigate to My Profile (
/profile) - Scroll down to the "API Tokens" section
- Click "Create Token"
- Give your token a descriptive name (e.g., "Mobile App", "Integration")
- Click the token field to copy it - it won't be shown again!
Using Your Token
Include your API token in the Authorization header of all API requests:
curl -H "Authorization: Bearer YOUR_API_TOKEN" \
https://your-tenant.usepresently.com/api/user
Important: Keep your API tokens secure. Never commit them to version control or share them publicly.
Base URL
All API requests should be made to:
https://your-tenant.usepresently.com/api/
Replace your-tenant with your actual tenant slug.
Endpoints
User Information
Get Current User
Returns information about the authenticated user.
GET /api/user
Response:
{
"id": 1,
"name": "John Doe",
"email": "john@example.com",
"tenant_id": 1,
"role": "tenant_admin",
"is_active": true,
"created_at": "2025-01-01T00:00:00.000000Z",
"tenant": {
"id": 1,
"name": "Dance Studio",
"slug": "dancestudio"
}
}
Families
List Families
Returns a paginated list of families.
GET /api/families
Query Parameters:
page(integer, optional): Page number for pagination (default: 1)
Response:
{
"data": [
{
"id": 1,
"name": "Smith Family",
"primary_contact_first_name": "Jane",
"primary_contact_last_name": "Smith",
"email": "jane@example.com",
"phone": "(555) 123-4567",
"students": [
{
"id": 1,
"first_name": "Emily",
"last_name": "Smith",
"date_of_birth": "2010-05-15"
}
]
}
],
"links": { ... },
"meta": { ... }
}
Get Single Family
Returns details for a specific family.
GET /api/families/{family_id}
Response:
{
"id": 1,
"name": "Smith Family",
"students": [ ... ],
"enrollments": [ ... ]
}
Students
List Students
Returns a paginated list of students.
GET /api/students
Query Parameters:
page(integer, optional): Page number for pagination (default: 1)
Response:
{
"data": [
{
"id": 1,
"first_name": "Emily",
"last_name": "Smith",
"date_of_birth": "2010-05-15",
"family": {
"id": 1,
"name": "Smith Family"
}
}
],
"links": { ... },
"meta": { ... }
}
Get Single Student
Returns details for a specific student.
GET /api/students/{student_id}
Response:
{
"id": 1,
"first_name": "Emily",
"last_name": "Smith",
"family": { ... },
"enrollments": [ ... ]
}
Classes
List Classes
Returns a paginated list of classes.
GET /api/classes
Query Parameters:
page(integer, optional): Page number for pagination (default: 1)
Response:
{
"data": [
{
"id": 1,
"name": "Ballet Level 1",
"season": {
"id": 1,
"name": "Fall 2025"
},
"class_type": {
"id": 1,
"name": "Ballet"
},
"location": {
"id": 1,
"name": "Studio A"
},
"schedules": [
{
"day_of_week": "Monday",
"start_time": "16:00:00",
"end_time": "17:00:00"
}
],
"instructors": [
{
"id": 1,
"first_name": "Sarah",
"last_name": "Johnson"
}
]
}
],
"links": { ... },
"meta": { ... }
}
Get Single Class
Returns details for a specific class including enrolled students.
GET /api/classes/{class_id}
Response:
{
"id": 1,
"name": "Ballet Level 1",
"season": { ... },
"enrollments": [
{
"id": 1,
"student": {
"id": 1,
"first_name": "Emily",
"last_name": "Smith"
}
}
]
}
Enrollments
List Enrollments
Returns a paginated list of enrollments.
GET /api/enrollments
Query Parameters:
page(integer, optional): Page number for pagination (default: 1)
Response:
{
"data": [
{
"id": 1,
"status": "active",
"student": {
"id": 1,
"first_name": "Emily",
"last_name": "Smith"
},
"class": {
"id": 1,
"name": "Ballet Level 1"
},
"family": {
"id": 1,
"name": "Smith Family"
}
}
],
"links": { ... },
"meta": { ... }
}
Get Single Enrollment
Returns details for a specific enrollment.
GET /api/enrollments/{enrollment_id}
Ledger Entries
List Ledger Entries
Returns a paginated list of ledger entries.
GET /api/ledger-entries
Query Parameters:
page(integer, optional): Page number for pagination (default: 1)
Response:
{
"data": [
{
"id": 1,
"family_id": 1,
"date": "2025-01-15",
"type": "charge",
"amount": 150.00,
"description": "January 2025 Tuition",
"family": {
"id": 1,
"name": "Smith Family"
},
"line_items": [
{
"id": 1,
"amount": 150.00,
"enrollment": {
"id": 1,
"student": {...},
"class": {...}
}
}
]
}
],
"links": { ... },
"meta": { ... }
}
Get Single Ledger Entry
Returns details for a specific ledger entry.
GET /api/ledger-entries/{ledger_entry_id}
Get Family Ledger Entries
Returns all ledger entries for a specific family.
GET /api/families/{family_id}/ledger-entries
Query Parameters:
page(integer, optional): Page number for pagination (default: 1)
Events
List Events
Returns a paginated list of events (performances, recitals).
GET /api/events
Query Parameters:
page(integer, optional): Page number for pagination (default: 1)
Response:
{
"data": [
{
"id": 1,
"name": "Spring Recital 2025",
"date": "2025-05-20",
"start_time": "18:00:00",
"end_time": "20:00:00",
"season": {
"id": 1,
"name": "Spring 2025"
},
"location": {
"id": 1,
"name": "Main Theater"
}
}
],
"links": { ... },
"meta": { ... }
}
Get Single Event
Returns details for a specific event including lineup and intermissions.
GET /api/events/{event_id}
Response:
{
"id": 1,
"name": "Spring Recital 2025",
"date": "2025-05-20",
"lineup_items": [
{
"id": 1,
"order": 1,
"class": {
"id": 1,
"name": "Ballet Level 1"
}
}
],
"intermissions": [
{
"id": 1,
"order": 5,
"title": "Intermission",
"duration": 15
}
]
}
Costumes
List Costumes
Returns a paginated list of all costumes.
GET /api/costumes
Query Parameters:
page(integer, optional): Page number for pagination (default: 1)
Response:
{
"data": [
{
"id": 1,
"name": "Pink Tutu",
"style_number": "PT-100",
"company": {
"id": 1,
"name": "Dance Costume Co."
}
}
],
"links": { ... },
"meta": { ... }
}
Get Single Costume
Returns details for a specific costume including available sizes and prices.
GET /api/costumes/{costume_id}
Get Family Costumes
Returns all costume assignments for students in a family.
GET /api/families/{family_id}/costumes
Response:
{
"family": {
"id": 1,
"name": "Smith Family"
},
"students": [
{
"id": 1,
"first_name": "Emily",
"last_name": "Smith",
"costumes": [
{
"id": 1,
"costume": {
"id": 1,
"name": "Pink Tutu",
"style_number": "PT-100"
},
"company_size": {
"id": 1,
"size": "Medium Child"
},
"quantity": 1,
"is_committed": true,
"committed_at": "2025-01-15T10:30:00.000000Z"
}
]
}
]
}
Instructors
List Instructors
GET /api/instructors
Response:
{
"data": [
{
"id": 1,
"first_name": "Sarah",
"last_name": "Johnson",
"display_name": "Miss Sarah",
"email": "sarah@example.com",
"phone": "(555) 000-0000",
"is_active": true
}
],
"links": { ... },
"meta": { ... }
}
Get Single Instructor
GET /api/instructors/{instructor_id}
Returns the instructor with their assigned classes.
Seasons
List Seasons
GET /api/seasons
Response:
{
"data": [
{
"id": 1,
"name": "Fall 2025",
"start_date": "2025-09-01",
"end_date": "2025-12-15",
"is_active": true
}
]
}
Get Single Season
GET /api/seasons/{season_id}
Returns the season with all its classes.
Class Types
List Class Types
GET /api/class-types
Returns class types with a summary of their attached rate group. Rate details are on the singular endpoint.
Get Single Class Type
GET /api/class-types/{class_type_id}
Returns the class type with the full rate group and every rate in it.
Class Schedules
List Class Schedules
GET /api/class-schedules
Returns every scheduled day/time slot across all classes, with the parent class and its location on each row.
Get Single Class Schedule
GET /api/class-schedules/{schedule_id}
Locations
List Locations
GET /api/locations
Get Single Location
GET /api/locations/{location_id}
Rate Groups
List Rate Groups
GET /api/rate-groups
Returns rate groups with all their rates inlined.
Get Single Rate Group
GET /api/rate-groups/{rate_group_id}
Returns the rate group with its rates AND sibling discounts.
List Rates for a Rate Group
GET /api/rate-groups/{rate_group_id}/rates
Just the rate rows for the group.
List Sibling Discounts for a Rate Group
GET /api/rate-groups/{rate_group_id}/sibling-discounts
Just the sibling-discount rows for the group.
Holidays
List Holidays
GET /api/holidays
Ordered by date.
Get Single Holiday
GET /api/holidays/{holiday_id}
Ledger Categories
List Ledger Categories
GET /api/ledger-categories
Categories that ledger entries can be tagged with (Tuition, Registration, Boutique, Late Fee, etc.).
Get Single Ledger Category
GET /api/ledger-categories/{category_id}
Family Payment Methods
List a Family's Payment Methods
GET /api/families/{family_id}/payment-methods
Returns every active payment method on file for the family (cards + ACH). No top-level /payment-methods endpoint — payment methods are always fetched per-family for privacy.
Response:
[
{
"id": 1,
"type": "card",
"brand": "visa",
"last4": "4242",
"exp_month": 12,
"exp_year": 2030,
"is_autopay": true,
"is_active": true
}
]
Attendance
List Attendance
GET /api/attendance
Query Parameters:
class_id(integer, optional): Filter to one classstudent_id(integer, optional): Filter to one studentdate_from(YYYY-MM-DD, optional): Inclusive lower bounddate_to(YYYY-MM-DD, optional): Inclusive upper boundpage(integer, optional)
Ordered most-recent first.
Get Single Attendance Record
GET /api/attendance/{attendance_id}
Drop-Ins
List Drop-Ins
GET /api/drop-ins
Get Single Drop-In
GET /api/drop-ins/{drop_in_id}
Makeup Classes
List Makeup Classes
GET /api/makeup-classes
Get Single Makeup
GET /api/makeup-classes/{makeup_id}
Communications
List Communications
GET /api/communications
Every email / SMS the studio has sent, most-recent first.
Get Single Communication
GET /api/communications/{communication_id}
Waivers
List Waivers
GET /api/waivers
Every waiver on the tenant with its season links.
Get Single Waiver
GET /api/waivers/{waiver_id}
Includes every acceptance row (family + timestamp + signature).
Boutique Items
List Boutique Items
GET /api/boutique-items
Response:
{
"data": [
{
"id": 1,
"name": "Class T-Shirt",
"price": "20.00",
"sales_tax_percentage": "8.00",
"tax_exempt": false,
"is_active": true,
"track_inventory": true,
"quantity_on_hand": 42
}
]
}
Get Single Boutique Item
GET /api/boutique-items/{item_id}
Returns the item with any images attached.
Boutique Sales
List Boutique Sales
GET /api/boutique-sales
Query Parameters:
family_id(integer, optional): Filter to one familydate_from(ISO 8601 datetime, optional): Sold at or afterdate_to(ISO 8601 datetime, optional): Sold at or beforepage(integer, optional)
Ordered most-recent first. Includes the family and boutique item on each row.
Get Single Boutique Sale
GET /api/boutique-sales/{sale_id}
Includes the family, item, and linked ledger entry.
Tags
List Tags
GET /api/tags
Studio-defined tags (applied to families / students / etc.).
Get Single Tag
GET /api/tags/{tag_id}
Custom Fields
List Custom Fields
GET /api/custom-fields
All custom fields defined on the tenant, ordered by target model then display order.
Get Single Custom Field
GET /api/custom-fields/{field_id}
Private Lesson Slots
List Private Lesson Slots
GET /api/private-lesson-slots
Query Parameters:
status(string, optional):open,booked,cancelled, etc.instructor_id(integer, optional): Filter to one instructorpage(integer, optional)
Get Single Slot
GET /api/private-lesson-slots/{slot_id}
Includes the instructor, location, and any bookings (with student + family).
Private Lesson Bookings
List Private Lesson Bookings
GET /api/private-lesson-bookings
Get Single Booking
GET /api/private-lesson-bookings/{booking_id}
Includes the slot (with instructor + location), the student, and the family.
Error Handling
The API uses standard HTTP status codes:
200 OK: Request succeeded401 Unauthorized: Missing or invalid API token403 Forbidden: Valid token but insufficient permissions404 Not Found: Resource not found422 Unprocessable Entity: Validation error500 Internal Server Error: Server error
Error Response Format:
{
"message": "Unauthenticated."
}
Rate Limiting
API requests are rate-limited to 60 requests per minute per token. If you exceed this limit, you'll receive a 429 Too Many Requests response.
Pagination
List endpoints return paginated results with the following structure:
{
"data": [ ... ],
"links": {
"first": "https://your-tenant.usepresently.com/api/families?page=1",
"last": "https://your-tenant.usepresently.com/api/families?page=10",
"prev": null,
"next": "https://your-tenant.usepresently.com/api/families?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 10,
"per_page": 50,
"to": 50,
"total": 500
}
}
Examples
Python Example
import requests
API_TOKEN = "your_api_token_here"
BASE_URL = "https://your-tenant.usepresently.com/api"
headers = {
"Authorization": f"Bearer {API_TOKEN}",
"Accept": "application/json"
}
# Get all families
response = requests.get(f"{BASE_URL}/families", headers=headers)
families = response.json()
print(f"Found {families['meta']['total']} families")
# Get a specific student
student_id = 1
response = requests.get(f"{BASE_URL}/students/{student_id}", headers=headers)
student = response.json()
print(f"Student: {student['first_name']} {student['last_name']}")
JavaScript/Node.js Example
const axios = require('axios');
const API_TOKEN = 'your_api_token_here';
const BASE_URL = 'https://your-tenant.usepresently.com/api';
const api = axios.create({
baseURL: BASE_URL,
headers: {
'Authorization': `Bearer ${API_TOKEN}`,
'Accept': 'application/json'
}
});
// Get all classes
api.get('/classes')
.then(response => {
console.log(`Found ${response.data.meta.total} classes`);
})
.catch(error => {
console.error('Error:', error.response.data);
});
// Get a specific family
const familyId = 1;
api.get(`/families/${familyId}`)
.then(response => {
console.log(`Family: ${response.data.name}`);
});
cURL Example
# Get current user
curl -H "Authorization: Bearer YOUR_API_TOKEN" \
https://your-tenant.usepresently.com/api/user
# List families (page 2)
curl -H "Authorization: Bearer YOUR_API_TOKEN" \
"https://your-tenant.usepresently.com/api/families?page=2"
# Get specific class
curl -H "Authorization: Bearer YOUR_API_TOKEN" \
https://your-tenant.usepresently.com/api/classes/1
Security Best Practices
- Keep tokens secure: Store API tokens in environment variables, not in code
- Use HTTPS: Always use HTTPS for API requests
- Rotate tokens: Periodically delete old tokens and create new ones
- Principle of least privilege: Create separate tokens for different integrations
- Monitor usage: Check "Last Used" timestamps in the API Tokens page
Support
For API support or to request additional endpoints, contact your Presently administrator or visit the Presently documentation.