API reference
All endpoints, parameters and responses of the API, generated from the OpenAPI description.
This page is generated at build time from the same description that GET /v1/openapi.json serves. It therefore cannot drift from the API. How keys, permissions, pages and errors work is described under Getting started.
Base address: https://api.casttool.net
Machine-readable description (OpenAPI 3.1): https://api.casttool.net/v1/openapi.json
Endpoints
GET /v1/me
Tenant and scopes of the API key in use
Key scope: any valid key
Responses
200Tenant and scopes of the API key in useMe401Missing, unknown, revoked or expired API keyError403The key lacks the scope, or the tenant is suspendedError429Too many requestsError
GET /v1/models
List models, ordered by id
Key scope: models:read
Parameters
| Field | In | Type | Required | Notes |
|---|---|---|---|---|
limit | query | integer | Number of items on one page · default 50, minimum 1, maximum 100 | |
cursor | query | string | `nextCursor` of the previous page | |
status | query | "active" | "inactive" | Only models with this status |
Responses
200List models, ordered by idModelPage400Invalid inputError401Missing, unknown, revoked or expired API keyError403The key lacks the scope, or the tenant is suspendedError429Too many requestsError
POST /v1/models
Create a model. It starts inactive and is published in the dashboard.
Key scope: models:write
Request body (JSON)
| Field | Type | Required | Notes |
|---|---|---|---|
firstName | string | yes | minLength 1, maxLength 100 |
lastName | string | yes | minLength 1, maxLength 100 |
email | string (email) | yes | maxLength 254 |
mobile | string | null | maxLength 50 | |
landline | string | null | maxLength 50 | |
address | string | null | maxLength 500 | |
dateOfBirth | string (date) | null | ||
gender | string | null | maxLength 200 | |
pronouns | string | null | maxLength 200 | |
category | string | null | maxLength 200 | |
bodyType | string | null | maxLength 200 | |
eyeColor | string | null | maxLength 200 | |
hairColor | string | null | maxLength 200 | |
ethnicIdentity | string | null | maxLength 200 | |
hasDriverLicense | boolean | ||
specialFeatures | string | null | maxLength 5000 | |
currentLocation | string[] | maxItems 100 | |
dialects | string[] | maxItems 100 | |
ethnicOrigins | string[] | maxItems 100 | |
languages | string[] | maxItems 100 | |
nationalities | string[] | maxItems 100 | |
previousClients | string[] | maxItems 100 | |
talents | string[] | maxItems 100 | |
measurements | object | ||
measurements.height | string | number | maxLength 40 | |
measurements.weight | string | number | maxLength 40 | |
measurements.bust | string | number | maxLength 40 | |
measurements.waist | string | number | maxLength 40 | |
measurements.hip | string | number | maxLength 40 | |
measurements.shoeSize | string | number | maxLength 40 | |
measurements.dressSize | string | number | maxLength 40 | |
measurements.jeansSize | string | number | maxLength 40 | |
socialMedia | object | ||
socialMedia.instagram | string | maxLength 300 | |
socialMedia.tiktok | string | maxLength 300 | |
socialMedia.youtube | string | maxLength 300 | |
socialMedia.twitch | string | maxLength 300 |
Responses
201Create a model. It starts inactive and is published in the dashboard. Without the scope `models:read` the response is `ModelWriteReceipt`.ModelResponse | ModelWriteReceipt400Invalid inputError401Missing, unknown, revoked or expired API keyError402The subscription only allows readingError403The key lacks the scope, or the tenant is suspendedError409The address is already registered in this tenantError429Too many requestsError
GET /v1/models/{id}
Read one model
Key scope: models:read
Parameters
| Field | In | Type | Required | Notes |
|---|---|---|---|---|
id | path | string | yes | Identifier of the resource |
Responses
200Read one modelModelResponse400Invalid inputError401Missing, unknown, revoked or expired API keyError403The key lacks the scope, or the tenant is suspendedError404Not found in this tenantError429Too many requestsError
PATCH /v1/models/{id}
Change the profile of a model. Status and visibility stay in the dashboard. A date of birth under 18 takes a public profile offline until a parent has given consent.
Key scope: models:write
Parameters
| Field | In | Type | Required | Notes |
|---|---|---|---|---|
id | path | string | yes | Identifier of the resource |
Request body (JSON)
| Field | Type | Required | Notes |
|---|---|---|---|
firstName | string | minLength 1, maxLength 100 | |
lastName | string | minLength 1, maxLength 100 | |
email | string (email) | maxLength 254 | |
mobile | string | null | maxLength 50 | |
landline | string | null | maxLength 50 | |
address | string | null | maxLength 500 | |
dateOfBirth | string (date) | null | ||
gender | string | null | maxLength 200 | |
pronouns | string | null | maxLength 200 | |
category | string | null | maxLength 200 | |
bodyType | string | null | maxLength 200 | |
eyeColor | string | null | maxLength 200 | |
hairColor | string | null | maxLength 200 | |
ethnicIdentity | string | null | maxLength 200 | |
hasDriverLicense | boolean | ||
specialFeatures | string | null | maxLength 5000 | |
currentLocation | string[] | maxItems 100 | |
dialects | string[] | maxItems 100 | |
ethnicOrigins | string[] | maxItems 100 | |
languages | string[] | maxItems 100 | |
nationalities | string[] | maxItems 100 | |
previousClients | string[] | maxItems 100 | |
talents | string[] | maxItems 100 | |
measurements | object | ||
measurements.height | string | number | maxLength 40 | |
measurements.weight | string | number | maxLength 40 | |
measurements.bust | string | number | maxLength 40 | |
measurements.waist | string | number | maxLength 40 | |
measurements.hip | string | number | maxLength 40 | |
measurements.shoeSize | string | number | maxLength 40 | |
measurements.dressSize | string | number | maxLength 40 | |
measurements.jeansSize | string | number | maxLength 40 | |
socialMedia | object | ||
socialMedia.instagram | string | maxLength 300 | |
socialMedia.tiktok | string | maxLength 300 | |
socialMedia.youtube | string | maxLength 300 | |
socialMedia.twitch | string | maxLength 300 |
Responses
200Change the profile of a model. Status and visibility stay in the dashboard. A date of birth under 18 takes a public profile offline until a parent has given consent. Without the scope `models:read` the response is `ModelWriteReceipt`.ModelResponse | ModelWriteReceipt400Invalid inputError401Missing, unknown, revoked or expired API keyError402The subscription only allows readingError403The key lacks the scope, or the tenant is suspendedError404Not found in this tenantError409The address is already registered in this tenantError429Too many requestsError
GET /v1/inquiries
List inquiries, ordered by id
Key scope: inquiries:read
Parameters
| Field | In | Type | Required | Notes |
|---|---|---|---|---|
limit | query | integer | Number of items on one page · default 50, minimum 1, maximum 100 | |
cursor | query | string | `nextCursor` of the previous page | |
status | query | "open" | "accepted" | "rejected" | "booked" | Only inquiries with this status |
Responses
200List inquiries, ordered by idInquiryPage400Invalid inputError401Missing, unknown, revoked or expired API keyError403The key lacks the scope, or the tenant is suspendedError429Too many requestsError
GET /v1/inquiries/{id}
Read one inquiry
Key scope: inquiries:read
Parameters
| Field | In | Type | Required | Notes |
|---|---|---|---|---|
id | path | string | yes | Identifier of the resource |
Responses
200Read one inquiryInquiryResponse400Invalid inputError401Missing, unknown, revoked or expired API keyError403The key lacks the scope, or the tenant is suspendedError404Not found in this tenantError429Too many requestsError
GET /v1/bookings
List confirmed bookings, ordered by id
Key scope: bookings:read
Parameters
| Field | In | Type | Required | Notes |
|---|---|---|---|---|
limit | query | integer | Number of items on one page · default 50, minimum 1, maximum 100 | |
cursor | query | string | `nextCursor` of the previous page |
Responses
200List confirmed bookings, ordered by idBookingPage400Invalid inputError401Missing, unknown, revoked or expired API keyError403The key lacks the scope, or the tenant is suspendedError429Too many requestsError
GET /v1/bookings/{id}
Read one confirmed booking
Key scope: bookings:read
Parameters
| Field | In | Type | Required | Notes |
|---|---|---|---|---|
id | path | string | yes | Identifier of the resource |
Responses
200Read one confirmed bookingBookingResponse400Invalid inputError401Missing, unknown, revoked or expired API keyError403The key lacks the scope, or the tenant is suspendedError404Not found in this tenantError429Too many requestsError
Responses in detail
Error
| Field | Type | Required | Notes |
|---|---|---|---|
error | object | yes | |
error.code | string | yes | Stable, machine-readable reason |
error.message | string | yes | |
error.issues | object[] | Only for `validation_failed` | |
error.issues[].path | string | yes | |
error.issues[].message | string | yes |
Me
| Field | Type | Required | Notes |
|---|---|---|---|
tenant | object | yes | |
tenant.id | string (uuid) | yes | |
tenant.slug | string | yes | |
tenant.name | string | yes | |
tenant.kind | "agency" | "casting" | yes | |
key | object | yes | |
key.id | string | yes | |
key.scopes | "models:read" | "models:private" | "models:write" | "inquiries:read" | "bookings:read"[] | yes |
ModelPage
| Field | Type | Required | Notes |
|---|---|---|---|
data | object[] | yes | |
data[].id | string | yes | |
data[].firstName | string | yes | |
data[].lastName | string | yes | |
data[].status | "active" | "inactive" | yes | |
data[].isPublic | boolean | yes | |
data[].featured | boolean | yes | |
data[].category | string | null | yes | |
data[].age | integer | null | yes | Only for public models |
data[].gender | string | null | yes | |
data[].pronouns | string | null | yes | |
data[].bodyType | string | null | yes | |
data[].eyeColor | string | null | yes | |
data[].hairColor | string | null | yes | |
data[].hasDriverLicense | boolean | yes | |
data[].specialFeatures | string | null | yes | |
data[].currentLocation | string[] | yes | |
data[].languages | string[] | yes | |
data[].dialects | string[] | yes | |
data[].nationalities | string[] | yes | |
data[].talents | string[] | yes | |
data[].previousClients | string[] | yes | |
data[].measurements | object | yes | |
data[].measurements.height | string | ||
data[].measurements.weight | string | ||
data[].measurements.bust | string | ||
data[].measurements.waist | string | ||
data[].measurements.hip | string | ||
data[].measurements.shoeSize | string | ||
data[].measurements.dressSize | string | ||
data[].measurements.jeansSize | string | ||
data[].socialMedia | object | yes | |
data[].socialMedia.instagram | string | ||
data[].socialMedia.tiktok | string | ||
data[].socialMedia.youtube | string | ||
data[].socialMedia.twitch | string | ||
data[].images | object | yes | Published images only. Files waiting for approval have no address here. |
data[].images.profileImage | string (uri) | null | yes | |
data[].images.galleryImages | string (uri)[] | yes | |
data[].private | object | Only with the scope `models:private` | |
data[].private.email | string | null | yes | |
data[].private.mobile | string | null | yes | |
data[].private.landline | string | null | yes | |
data[].private.address | string | null | yes | |
data[].private.dateOfBirth | string | null | yes | |
data[].private.ethnicIdentity | string | null | yes | |
data[].private.ethnicOrigins | string[] | yes | |
data[].createdAt | string (date-time) | yes | |
data[].updatedAt | string (date-time) | yes | |
nextCursor | string | null | yes | Pass as `cursor` for the next page, null on the last one |
ModelResponse
| Field | Type | Required | Notes |
|---|---|---|---|
model | object | yes | |
model.id | string | yes | |
model.firstName | string | yes | |
model.lastName | string | yes | |
model.status | "active" | "inactive" | yes | |
model.isPublic | boolean | yes | |
model.featured | boolean | yes | |
model.category | string | null | yes | |
model.age | integer | null | yes | Only for public models |
model.gender | string | null | yes | |
model.pronouns | string | null | yes | |
model.bodyType | string | null | yes | |
model.eyeColor | string | null | yes | |
model.hairColor | string | null | yes | |
model.hasDriverLicense | boolean | yes | |
model.specialFeatures | string | null | yes | |
model.currentLocation | string[] | yes | |
model.languages | string[] | yes | |
model.dialects | string[] | yes | |
model.nationalities | string[] | yes | |
model.talents | string[] | yes | |
model.previousClients | string[] | yes | |
model.measurements | object | yes | |
model.measurements.height | string | ||
model.measurements.weight | string | ||
model.measurements.bust | string | ||
model.measurements.waist | string | ||
model.measurements.hip | string | ||
model.measurements.shoeSize | string | ||
model.measurements.dressSize | string | ||
model.measurements.jeansSize | string | ||
model.socialMedia | object | yes | |
model.socialMedia.instagram | string | ||
model.socialMedia.tiktok | string | ||
model.socialMedia.youtube | string | ||
model.socialMedia.twitch | string | ||
model.images | object | yes | Published images only. Files waiting for approval have no address here. |
model.images.profileImage | string (uri) | null | yes | |
model.images.galleryImages | string (uri)[] | yes | |
model.private | object | Only with the scope `models:private` | |
model.private.email | string | null | yes | |
model.private.mobile | string | null | yes | |
model.private.landline | string | null | yes | |
model.private.address | string | null | yes | |
model.private.dateOfBirth | string | null | yes | |
model.private.ethnicIdentity | string | null | yes | |
model.private.ethnicOrigins | string[] | yes | |
model.createdAt | string (date-time) | yes | |
model.updatedAt | string (date-time) | yes |
ModelWriteReceipt
| Field | Type | Required | Notes |
|---|---|---|---|
model | object | yes | Without the scope `models:read` only id and timestamp, the profile stays unreadable |
model.id | string | yes | |
model.updatedAt | string (date-time) | yes |
InquiryPage
| Field | Type | Required | Notes |
|---|---|---|---|
data | object[] | yes | |
data[].id | string | yes | |
data[].status | "open" | "accepted" | "rejected" | "booked" | yes | |
data[].offerStatus | "pending" | "accepted" | "rejected" | null | yes | |
data[].name | string | null | yes | |
data[].email | string | null | yes | |
data[].phone | string | null | yes | |
data[].company | string | null | yes | |
data[].contactPerson | string | null | yes | |
data[].project | string | null | yes | |
data[].category | string | null | yes | |
data[].type | string | null | yes | |
data[].poNumber | string | null | yes | |
data[].budget | object | yes | |
data[].budget.dailyFee | string | null | yes | |
data[].budget.travelAndFitting | string | null | yes | |
data[].budget.overtime | string | null | yes | |
data[].budget.buyout | string | null | yes | |
data[].fittingDate | object | yes | |
data[].fittingDate.date | string | null | yes | |
data[].fittingDate.location | string | null | yes | |
data[].fittingDate.description | string | null | yes | |
data[].recallDate | object | yes | |
data[].recallDate.date | string | null | yes | |
data[].recallDate.location | string | null | yes | |
data[].recallDate.description | string | null | yes | |
data[].shootingDates | object[] | yes | |
data[].shootingDates[].date | string | null | yes | |
data[].shootingDates[].location | string | null | yes | |
data[].shootingDates[].description | string | null | yes | |
data[].models | object[] | yes | |
data[].models[].id | string | yes | |
data[].models[].name | string | yes | |
data[].models[].responseStatus | "pending" | "available" | "tentative" | "booked" | "unavailable" | yes | |
data[].models[].respondedAt | string (date-time) | null | yes | |
data[].createdAt | string (date-time) | yes | |
data[].updatedAt | string (date-time) | yes | |
nextCursor | string | null | yes | Pass as `cursor` for the next page, null on the last one |
InquiryResponse
| Field | Type | Required | Notes |
|---|---|---|---|
inquiry | object | yes | |
inquiry.id | string | yes | |
inquiry.status | "open" | "accepted" | "rejected" | "booked" | yes | |
inquiry.offerStatus | "pending" | "accepted" | "rejected" | null | yes | |
inquiry.name | string | null | yes | |
inquiry.email | string | null | yes | |
inquiry.phone | string | null | yes | |
inquiry.company | string | null | yes | |
inquiry.contactPerson | string | null | yes | |
inquiry.project | string | null | yes | |
inquiry.category | string | null | yes | |
inquiry.type | string | null | yes | |
inquiry.poNumber | string | null | yes | |
inquiry.budget | object | yes | |
inquiry.budget.dailyFee | string | null | yes | |
inquiry.budget.travelAndFitting | string | null | yes | |
inquiry.budget.overtime | string | null | yes | |
inquiry.budget.buyout | string | null | yes | |
inquiry.fittingDate | object | yes | |
inquiry.fittingDate.date | string | null | yes | |
inquiry.fittingDate.location | string | null | yes | |
inquiry.fittingDate.description | string | null | yes | |
inquiry.recallDate | object | yes | |
inquiry.recallDate.date | string | null | yes | |
inquiry.recallDate.location | string | null | yes | |
inquiry.recallDate.description | string | null | yes | |
inquiry.shootingDates | object[] | yes | |
inquiry.shootingDates[].date | string | null | yes | |
inquiry.shootingDates[].location | string | null | yes | |
inquiry.shootingDates[].description | string | null | yes | |
inquiry.models | object[] | yes | |
inquiry.models[].id | string | yes | |
inquiry.models[].name | string | yes | |
inquiry.models[].responseStatus | "pending" | "available" | "tentative" | "booked" | "unavailable" | yes | |
inquiry.models[].respondedAt | string (date-time) | null | yes | |
inquiry.createdAt | string (date-time) | yes | |
inquiry.updatedAt | string (date-time) | yes |
BookingPage
| Field | Type | Required | Notes |
|---|---|---|---|
data | object[] | yes | |
data[].id | string | yes | |
data[].inquiryId | string | yes | |
data[].terms | object | yes | |
data[].terms.dailyFee | string | null | yes | |
data[].terms.travelAndFitting | string | null | yes | |
data[].terms.overtime | string | null | yes | |
data[].terms.buyout | string | null | yes | |
data[].models | object[] | yes | |
data[].models[].id | string | yes | |
data[].models[].name | string | yes | |
data[].confirmedAt | string (date-time) | yes | |
nextCursor | string | null | yes | Pass as `cursor` for the next page, null on the last one |
BookingResponse
| Field | Type | Required | Notes |
|---|---|---|---|
booking | object | yes | |
booking.id | string | yes | |
booking.inquiryId | string | yes | |
booking.terms | object | yes | |
booking.terms.dailyFee | string | null | yes | |
booking.terms.travelAndFitting | string | null | yes | |
booking.terms.overtime | string | null | yes | |
booking.terms.buyout | string | null | yes | |
booking.models | object[] | yes | |
booking.models[].id | string | yes | |
booking.models[].name | string | yes | |
booking.confirmedAt | string (date-time) | yes |