Skip to main content
GET
/
api
/
calendar
/
v1
/
public
/
org
/
{org_slug}
/
service
/
{service_slug}
Get Service
curl --request GET \
  --url https://api.example.com/api/calendar/v1/public/org/{org_slug}/service/{service_slug} \
  --header 'x-kordless-key: <x-kordless-key>'
{
  "401": {},
  "404": {},
  "429": {},
  "organization": {
    "id": "<string>",
    "name": "<string>",
    "slug": "<string>",
    "branding": {}
  },
  "service": {
    "key": "<string>",
    "name": "<string>",
    "slug": "<string>",
    "description": "<string>",
    "category": "<string>",
    "duration": 123,
    "price": 123,
    "currency": "<string>",
    "isBookablePublic": true,
    "metadata": {}
  },
  "calendarSettings": {
    "duration_minutes": 123,
    "slot_interval_minutes": 123,
    "buffer_before": 123,
    "buffer_after": 123,
    "booking_window_days": 123,
    "timezone": "<string>",
    "location": {},
    "max_parallel_bookings": 123,
    "cancellation_policy": {}
  }
}

Endpoint

GET https://api.kordless.ai/api/calendar/v1/public/org/{org_slug}/service/{service_slug}
Retrieves detailed information about a specific service, including calendar settings like duration, buffer times, and location.

Authentication

x-kordless-key
string
required
Your API key

Path Parameters

org_slug
string
required
Your organization slugExample: acme-salon
service_slug
string
required
The service slugExample: haircut

Response

organization
object
Organization information
service
object
Service details
calendarSettings
object
Calendar configuration for this service

Examples

curl https://api.kordless.ai/api/calendar/v1/public/org/acme-salon/service/haircut \
  -H "x-kordless-key: your_api_key"

Response Example

{
  "organization": {
    "id": "org_abc123",
    "name": "Acme Salon",
    "slug": "acme-salon",
    "branding": {
      "primaryColor": "#6366f1",
      "logo": "https://storage.example.com/acme-logo.png",
      "companyName": "Acme Salon & Spa"
    }
  },
  "service": {
    "key": "haircut",
    "name": "Haircut",
    "slug": "haircut",
    "description": "Professional haircut with wash and style",
    "category": "Hair",
    "duration": 60,
    "price": 45.00,
    "currency": "USD",
    "isBookablePublic": true,
    "metadata": {}
  },
  "calendarSettings": {
    "duration_minutes": 60,
    "slot_interval_minutes": 30,
    "buffer_before": 0,
    "buffer_after": 15,
    "booking_window_days": 30,
    "timezone": "America/New_York",
    "location": {
      "type": "onsite",
      "value": "123 Main St, Suite 100, New York, NY 10001"
    },
    "max_parallel_bookings": 1,
    "cancellation_policy": {
      "noticeHours": 24,
      "policyText": "Please cancel at least 24 hours in advance to avoid a cancellation fee."
    }
  }
}

Building a Service Detail Page

function ServiceDetail({ orgSlug, serviceSlug, onBook }) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    getService(orgSlug, serviceSlug)
      .then(setData)
      .finally(() => setLoading(false));
  }, [orgSlug, serviceSlug]);

  if (loading) return <Spinner />;
  if (!data) return <NotFound />;

  const { organization, service, calendarSettings } = data;

  return (
    <div className="service-detail">
      <header>
        <h1>{service.name}</h1>
        <p className="org-name">{organization.name}</p>
      </header>

      <section className="details">
        <p className="description">{service.description}</p>

        <div className="info-grid">
          <div className="info-item">
            <span className="label">Duration</span>
            <span className="value">{service.duration} minutes</span>
          </div>

          {service.price && (
            <div className="info-item">
              <span className="label">Price</span>
              <span className="value">
                ${service.price.toFixed(2)} {service.currency}
              </span>
            </div>
          )}

          {calendarSettings.location && (
            <div className="info-item">
              <span className="label">Location</span>
              <span className="value">
                {calendarSettings.location.type === 'onsite' && '📍 '}
                {calendarSettings.location.type === 'phone' && '📞 '}
                {calendarSettings.location.type === 'meet_url' && '💻 '}
                {calendarSettings.location.value}
              </span>
            </div>
          )}
        </div>

        {calendarSettings.cancellation_policy?.policyText && (
          <div className="cancellation-policy">
            <h3>Cancellation Policy</h3>
            <p>{calendarSettings.cancellation_policy.policyText}</p>
          </div>
        )}
      </section>

      <button onClick={onBook} className="book-button">
        Book {service.name}
      </button>
    </div>
  );
}

Using Calendar Settings

The calendar settings help you build accurate booking experiences:
const { calendarSettings } = await getService(orgSlug, serviceSlug);

// Calculate booking window
const maxBookingDate = new Date();
maxBookingDate.setDate(maxBookingDate.getDate() + calendarSettings.booking_window_days);

// Show location appropriately
function formatLocation(location) {
  switch (location.type) {
    case 'onsite':
      return `In-person at ${location.value}`;
    case 'phone':
      return `Phone call to ${location.value}`;
    case 'meet_url':
      return `Video call: ${location.value}`;
    default:
      return location.value;
  }
}

// Display cancellation policy
if (calendarSettings.cancellation_policy) {
  const { noticeHours, policyText } = calendarSettings.cancellation_policy;
  showPolicy({
    title: `${noticeHours}-hour cancellation notice required`,
    details: policyText
  });
}

Errors

401
Unauthorized
Invalid or missing API key
{
  "detail": "Missing x-kordless-key header"
}
404
Not Found
Organization or service not found
{
  "detail": "Service not found"
}
429
Too Many Requests
Rate limit exceeded