10xDotIn Product Docs

Handle Booking Page with Scheduling

Build a public handle page, such as arjun.10x.in, that lets visitors book time through native 10x Scheduling.

Handle Booking Page with Scheduling

Use this guide when a developer needs to build a public handle page, such as https://arjun.10x.in, with a clear option for visitors to book time through native 10x Scheduling.

The general Scheduling guide already exists at Scheduling. This page is the implementation handoff for the handle-page use case: page structure, API sequence, booking link behavior, inline slot-picker behavior, and rollout checks.

For the first version, publish the handle page and link its primary booking CTA to the first-party Scheduling page:

https://app.10x.in/apps/public/scheduling/{handle}/{eventSlug}

Example:

https://app.10x.in/apps/public/scheduling/arjun/intro-call

This keeps the custom profile page simple while 10x owns slot selection, booking creation, payment redirect, cancellation, rescheduling, calendar sync, confirmation email, and webhook side effects.

If the design requires slots directly on arjun.10x.in, build an inline picker with the public Scheduling API. Keep a fallback link to the first-party Scheduling page for degraded states.

Page Structure

Use this structure for a handle profile or creator booking page:

handle: arjun
publicHost: https://arjun.10x.in
page:
  path: /
  primaryAction: book_time
  scheduling:
    eventSlug: intro-call
    mode: link_first
    publicBookingPath: /apps/public/scheduling/arjun/intro-call
    fallbackLabel: Book a time
content:
  headline: Work with Arjun
  proof: selected outcomes, testimonials, or examples
  offer: 30-minute intro call
  expectation: what the visitor should prepare before booking
analytics:
  source: handle_profile
  tracking:
    page: profile
    placement: hero_cta

The public page should include:

SectionPurpose
IdentityHandle owner name, role, and what visitors can book.
ProofOutcomes, examples, testimonials, or trust signals.
OfferEvent title, duration, price if paid, and who the session is for.
Booking CTALink to /apps/public/scheduling/{handle}/{eventSlug} or inline slot picker.
FallbackLead form, email, or request-follow-up CTA if scheduling is unavailable.
AttributionSource metadata for analytics or downstream follow-up.

Integration Options

OptionBest forImplementation
Link-first CTAMost pages and fastest launchButton links to the first-party Scheduling page.
Inline pickerHigh-control branded pagesPage calls the public Scheduling API and creates bookings itself.
HybridRecommended for important profilesShow key times inline and keep a fallback link to the first-party page.

Do not iframe the first-party Scheduling page unless the current deployment explicitly allows framing. Prefer a link or API-driven inline component.

Owner Setup

The handle owner or a creator with access sets up the event type in Product Suite, or an internal tool can call the owner APIs with a signed-in JWT.

Required owner access:

  • Handle: arjun
  • Role: CREATOR or higher
  • Auth: control-plane JWT
  • Optional integrations: Google Calendar/Meet, Office365 Calendar/Video, CalDAV, Zoom, Stripe, custom CALENDAR sender profile

1. Create or Confirm Availability

If no schedule exists, Scheduling falls back to a default weekday schedule. Create an explicit schedule when the page needs a named time zone or custom hours.

export TENX_API_BASE="https://ai.10x.in"
export TENX_HANDLE="arjun"
export TENX_JWT="<creator-jwt>"

curl -sS -X POST "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/scheduling/schedules" \
  -H "Authorization: Bearer ${TENX_JWT}" \
  -H "Content-Type: application/json" \
  -d '{
    "scheduleId": "default",
    "timeZone": "Asia/Kolkata",
    "weeklyAvailability": [
      { "day": 1, "startTime": "10:00", "endTime": "17:00" },
      { "day": 2, "startTime": "10:00", "endTime": "17:00" },
      { "day": 3, "startTime": "10:00", "endTime": "17:00" },
      { "day": 4, "startTime": "10:00", "endTime": "17:00" },
      { "day": 5, "startTime": "10:00", "endTime": "17:00" }
    ],
    "overrides": []
  }'

day uses JavaScript weekday numbering: 0 is Sunday, 1 is Monday, and 6 is Saturday.

2. Create the Event Type Hidden

Create the event type as hidden first. Hidden or draft events are not public, so the public booking URL returns 404 until the event is published.

curl -sS -X POST "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/scheduling/event-types" \
  -H "Authorization: Bearer ${TENX_JWT}" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "intro-call",
    "title": "30-minute intro call",
    "description": "Use this call to scope the problem, decide next steps, and confirm whether 10x/OpenAnalyst is a fit.",
    "durationMinutes": 30,
    "timeZone": "Asia/Kolkata",
    "scheduleId": "default",
    "hidden": true,
    "confirmationRequired": false,
    "minimumNoticeMinutes": 120,
    "buffers": {
      "beforeMinutes": 10,
      "afterMinutes": 10
    },
    "locations": [
      {
        "type": "google_meet",
        "label": "Google Meet"
      }
    ],
    "bookingFields": [
      {
        "id": "topic",
        "label": "What should we discuss?",
        "type": "textarea",
        "required": true
      }
    ],
    "payment": {
      "enabled": false
    }
  }'

Save the returned eventType.eventTypeId. The public URL uses slug, but updates use eventTypeId.

3. Connect Calendars and Meeting Providers

Use Product Suite when possible. For API-driven setup:

JobMethod and path
List providers and credentialsGET /v2/handles/{handle}/scheduling/integrations
Start OAuthPOST /v2/handles/{handle}/scheduling/integrations/{providerKey}/oauth/start
Complete OAuthPOST /v2/handles/{handle}/scheduling/integrations/{providerKey}/oauth/callback
Add CalDAV credentialPOST /v2/handles/{handle}/scheduling/integrations/caldav/credentials
List provider calendarsGET /v2/handles/{handle}/scheduling/integrations/{providerKey}/calendars
Select busy calendarsPOST /v2/handles/{handle}/scheduling/selected-calendars
Disconnect credentialDELETE /v2/handles/{handle}/scheduling/integrations/{providerKey}/credentials/{credentialId}

Supported provider keys are google, office365, caldav, zoom, and stripe. Stripe uses the existing billing secret and only matters when the event type has payment.enabled: true.

4. Publish the Event Type

After QA confirms the event details, availability, calendar connection, and page CTA, publish the event by setting hidden to false.

export EVENT_TYPE_ID="<returned-event-type-id>"

curl -sS -X PUT "${TENX_API_BASE}/v2/handles/${TENX_HANDLE}/scheduling/event-types/${EVENT_TYPE_ID}" \
  -H "Authorization: Bearer ${TENX_JWT}" \
  -H "Content-Type: application/json" \
  -d '{
    "hidden": false
  }'

The event becomes public only when it is not hidden and has status: "ACTIVE".

Use this when the page only needs a booking button.

<section class="profile-booking">
  <p class="eyebrow">Available for consultations</p>
  <h1>Work with Arjun</h1>
  <p>
    Book a 30-minute intro call to scope the problem, decide next steps, and
    confirm whether a 10x or OpenAnalyst workflow is the right fit.
  </p>
  <a
    class="button primary"
    href="https://app.10x.in/apps/public/scheduling/arjun/intro-call"
  >
    Book a time
  </a>
  <a class="button secondary" href="/contact">
    Request follow-up instead
  </a>
</section>

Acceptance criteria:

  • The CTA uses the correct handle and eventSlug.
  • The public booking URL returns the event, not 404.
  • The first-party page shows slots in the expected time zone.
  • Paid events redirect to Stripe and return to the Scheduling page after checkout.
  • The handle page includes a fallback when no slots are available.

Inline Slot Picker

Use the public Scheduling API only when the handle page needs to show slots without sending the visitor to the first-party page first.

Public endpoints:

JobMethod and pathAuth
List public event typesGET /v2/public/scheduling/{handle}None
Read one event typeGET /v2/public/scheduling/{handle}/{eventSlug}None
List slotsGET /v2/public/scheduling/{handle}/{eventSlug}/slots?start={iso}&end={iso}None
Create bookingPOST /v2/public/scheduling/{handle}/{eventSlug}/bookingsNone
Cancel bookingPOST /v2/public/scheduling/{handle}/{eventSlug}/bookings/{bookingUid}/cancelNone
Reschedule bookingPOST /v2/public/scheduling/{handle}/{eventSlug}/rescheduleNone

Load Event Metadata

curl -sS "${TENX_API_BASE}/v2/public/scheduling/arjun/intro-call"

Expected shape:

{
  "event": {
    "handle": "arjun",
    "eventTypeId": "evt_...",
    "slug": "intro-call",
    "title": "30-minute intro call",
    "description": "Use this call to scope the problem...",
    "duration": 30,
    "locations": [
      {
        "type": "google_meet",
        "label": "Google Meet"
      }
    ],
    "timeZone": "Asia/Kolkata",
    "bookingFields": [],
    "paymentRequired": false,
    "availableActions": ["book", "cancel", "reschedule"]
  }
}

Load Available Slots

curl -sS "${TENX_API_BASE}/v2/public/scheduling/arjun/intro-call/slots?start=2026-06-08T00:00:00.000Z&end=2026-06-15T00:00:00.000Z"

Expected shape:

{
  "slots": [
    {
      "start": "2026-06-09T05:00:00.000Z",
      "end": "2026-06-09T05:30:00.000Z",
      "timeZone": "Asia/Kolkata",
      "sourceAvailability": {
        "kind": "weekly",
        "label": "2:10:00-17:00"
      },
      "bookingNonce": "slot_..."
    }
  ],
  "displayTimeZone": "Asia/Kolkata"
}

Create a Booking

curl -sS -X POST "${TENX_API_BASE}/v2/public/scheduling/arjun/intro-call/bookings" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: arjun-intro-20260609T050000Z-lead@example.com" \
  -d '{
    "attendee": {
      "name": "Rishabh",
      "email": "lead@example.com",
      "timeZone": "Asia/Kolkata"
    },
    "slot": {
      "start": "2026-06-09T05:00:00.000Z",
      "end": "2026-06-09T05:30:00.000Z"
    },
    "answers": {
      "topic": "We want to discuss an AI sales workflow."
    },
    "guests": [],
    "tracking": {
      "source": "handle_profile",
      "placement": "hero_cta"
    }
  }'

Possible booking statuses:

StatusMeaning
ACCEPTEDConfirmed immediately. Calendar/video side effects are attempted.
PENDINGSaved, but owner confirmation is required.
PENDING_PAYMENTSaved, but Stripe checkout must complete before confirmation.
CANCELLEDBooking was cancelled.
REJECTEDBooking was rejected or checkout failed before confirmation.

If the response includes:

{
  "nextAction": {
    "type": "redirect_to_checkout",
    "url": "https://checkout.stripe.com/..."
  }
}

redirect the visitor to nextAction.url.

Browser Skeleton

<div
  id="tenx-inline-scheduler"
  data-api-base="https://ai.10x.in"
  data-handle="arjun"
  data-event-slug="intro-call"
></div>

The skeleton intentionally omits styling and rendering. The developer should render slot buttons, validate name/email before booking, display error states, and handle nextAction.redirect_to_checkout.

Webhooks and Follow-Up

Use Scheduling webhooks when a booking should notify a CRM, Slack workflow, operator queue, or custom fulfillment system.

Owner API:

POST /v2/handles/{handle}/scheduling/webhooks

Supported events:

  • scheduling.booking.created
  • scheduling.booking.confirmed
  • scheduling.booking.cancelled
  • scheduling.booking.rescheduled
  • scheduling.payment.required
  • scheduling.payment.succeeded
  • scheduling.sync.degraded

For delivery behavior, see Webhook Delivery and Failure Handling.

Rollout Checklist

Before handing the page to a visitor:

  • Confirm the handle host resolves, for example https://arjun.10x.in.
  • Confirm the page CTA uses the intended handle and eventSlug.
  • Confirm GET /v2/public/scheduling/{handle}/{eventSlug} returns 200.
  • Confirm slots appear for the next seven days.
  • Create a test booking with a real email address.
  • For paid events, complete a Stripe checkout and confirm the booking moves from PENDING_PAYMENT to ACCEPTED.
  • For connected calendars, confirm unavailable external calendar blocks are removed from the slot list.
  • Confirm booking confirmation, reschedule, and cancellation emails use the intended sender.
  • Confirm any webhooks receive the expected scheduling.* payloads.
  • Confirm the handle page has a fallback lead form or contact CTA when Scheduling is unavailable.

Troubleshooting

SymptomLikely causeFix
Public booking URL returns 404Event is still hidden, not active, or the slug is wrong.Publish the event with hidden: false and verify the slug.
Slots are emptyWeekly availability, date overrides, minimum notice, buffers, or selected calendars remove all slots.Check the event schedule and busy-calendar selections.
Booking returns booking_required_fieldsMissing attendee name, attendee email, slot start, or slot end.Validate the inline form before posting.
Booking returns scheduling_slot_unavailableAnother booking reserved the slot or the requested slot was not generated by availability.Reload slots and ask the visitor to choose again.
Paid booking does not confirmStripe checkout did not complete or the webhook completion was not processed.Inspect the booking, checkout session, and scheduling.payment.* webhook events.
Calendar sync is degradedProvider side effects failed after the booking was saved.Keep the booking and reconnect the provider or handle follow-up manually.

Related:

Updated Jun 19, 2026