FS-DOC-05Technical
Integration and API Spec
Appointment / Booking Management
[YourCompany.com] · Operations Department · Prepared by FullSpec · [Today's Date]
This document is the authoritative technical reference for every integration point in the Appointment and Booking Management automation. It covers the full tool inventory, per-tool authentication and scope requirements, field mappings between agents, orchestration layout, credential storage, and defined failure behaviour for every integration. The FullSpec team uses this spec during build and QA; it remains the source of truth for any future change or extension to the automation.
01Tool inventory
Tool
Role in automation
Auth method
Min plan required
Used by agents
Orchestration layer
Hosts all workflows, credential store, triggers, and inter-agent data passing
Internal (platform admin)
Paid tier with webhook and API step support
All agents
Calendly
Self-serve booking page; availability check; booking event webhook source
OAuth 2.0
Standard ($16/mo)
Agent 1
Google Calendar
Live calendar event creation; buffer time enforcement
OAuth 2.0 (Google)
Google Workspace or free Gmail
Agent 1
Gmail
Confirmation emails, reminder emails, no-show follow-up emails
OAuth 2.0 (Google)
Google Workspace or free Gmail
Agents 1, 2, 3
HubSpot
Contact and deal record creation or update; booking status logging; no-show flag
OAuth 2.0 / Private App Token
Starter CRM ($50/mo)
Agents 2, 3
Stripe
Deposit payment link generation; payment status webhook; booking confirmation on payment
API key (secret key + webhook signing secret)
Pay-as-you-go (no monthly fee)
Agent 2
Twilio
SMS reminders 48 hr and 2 hr before appointment
Account SID + Auth Token
Pay-as-you-go with A2P 10DLC registered number
Agent 3
Before you connect anything: test every integration against its sandbox or test environment using non-production credentials. For Stripe, use test-mode keys and the Stripe CLI to simulate webhook events. For Twilio, use a trial account and verified test numbers. For Calendly, HubSpot, and Google, use a staging account or a dedicated test calendar and CRM pipeline. Never point a live credential at an untested workflow step.
Integration and API SpecPage 1 of 4
FS-DOC-05Technical
02Per-tool integration detail
Calendly
Calendly is the entry point for all inbound booking requests. A webhook fires on every booking.created, booking.cancelled, and booking.rescheduled event and delivers the structured booking payload to the orchestration layer for Agent 1 processing.
Auth method
OAuth 2.0. Redirect URI must be registered in the Calendly developer portal. Access token expires in 2 hours; store and rotate the refresh token automatically via the credential store.
Required scopes
default (read user and event type data); webhook_subscription:read; webhook_subscription:write; scheduled_events:read; scheduled_events:write
Webhook setup
POST to https://api.calendly.com/webhook_subscriptions with scope=organization, events=[invitee.created, invitee.canceled], signing_key stored in credential store. Validate incoming requests using the X-Calendly-Webhook-Signature header (HMAC-SHA256). Reject any request that fails signature validation with HTTP 401.
Required configuration
Event type UUID(s) stored in the credential store (not hardcoded). Calendly organization URI stored in the credential store. If multiple event types are in scope, store each UUID with a human-readable label.
Rate limits
100 requests/minute on the Standard plan. At 120 bookings/month (roughly 4 per day), throttling is not required. Implement a 1-second delay between sequential API calls as a precaution.
Constraints
Calendly does not expose buffer times as a webhook field; buffer rules are configured inside Calendly and enforced there. Do not attempt to recalculate buffers in the orchestration layer. Cancellation and reschedule payloads arrive via the same invitee.canceled event; differentiate by checking the cancellation.reason and the presence of a rescheduled field.
Google Calendar
Google Calendar receives a structured event creation call from Agent 1 immediately after a booking is confirmed in Calendly. The calendar event is the operational record for staff availability.
Auth method
OAuth 2.0 via Google Identity Platform. Scopes granted at the Google Cloud Console OAuth consent screen. Store access token and refresh token in the credential store; access tokens expire in 3600 seconds.
Required scopes
https://www.googleapis.com/auth/calendar.events; https://www.googleapis.com/auth/calendar.readonly
Webhook / trigger setup
Google Calendar is used in push (write) mode only from the orchestration layer. No inbound webhook from Google Calendar is required in this automation.
Required configuration
Target calendar ID stored in the credential store (format: user@domain.com or the alphanumeric ID for a secondary calendar). If multiple staff calendars are in scope, store each ID with a label. Never hardcode the calendar ID.
Rate limits
Google Calendar API allows 1,000,000 queries/day and 500 write requests/100 seconds per user. At 120 bookings/month, throttling is not required. Standard exponential backoff applies on 429 responses.
Constraints
Event creation must include the client email in the attendees array to trigger a Google Calendar invite to the client. Set sendUpdates=none if the confirmation email is being handled exclusively by Gmail to avoid duplicate client notifications.
Gmail
Gmail sends all transactional emails in the automation: booking confirmation (Agent 1), deposit request and payment confirmation (Agent 2), reminder emails 48 hr and 2 hr before the appointment, and no-show follow-up (Agent 3). All emails use pre-approved templates stored in the credential/config store.
Auth method
OAuth 2.0 via Google Identity Platform. The sending Gmail address must be the account that grants OAuth consent. Store access and refresh tokens in the credential store.
Required scopes
https://www.googleapis.com/auth/gmail.send; https://www.googleapis.com/auth/gmail.compose
Webhook / trigger setup
Gmail is outbound-only in this automation. No Gmail push notification subscription is required. Agent 3 no-show detection is time-based, not inbox-polling-based.
Required configuration
Template IDs or raw HTML template strings stored in the config store with keys: TEMPLATE_CONFIRMATION, TEMPLATE_DEPOSIT_REQUEST, TEMPLATE_PAYMENT_CONFIRMED, TEMPLATE_REMINDER_48H, TEMPLATE_REMINDER_2H, TEMPLATE_NO_SHOW. All templates must use placeholder tokens (e.g. {{client_name}}, {{appointment_datetime}}, {{service_type}}, {{stripe_link}}) substituted at send time. From-name and reply-to address stored in config, not hardcoded.
Rate limits
Gmail API allows 250 quota units/second and 1,000,000,000 units/day. Sending a single message costs 100 units. At peak volume (120 bookings, up to 5 emails each = 600 emails/month), usage is negligible. No throttling required.
Constraints
Emails sent via the Gmail API are from the authenticated Google account. If a custom domain sender (e.g. bookings@yourdomain.com) is required, that address must be added as a Send As alias in the Gmail settings and verified before build. DKIM and SPF records must be valid on the sending domain.
HubSpot
HubSpot receives contact and deal records from Agent 2 and receives status updates (deposit confirmed, appointment no-show) from Agents 2 and 3. The automation uses the HubSpot CRM API v3.
Auth method
Private App Token (recommended over legacy API keys). Generate a Private App in HubSpot Settings > Integrations > Private Apps. Store the token in the credential store as HUBSPOT_PRIVATE_APP_TOKEN. Token does not expire but must be rotated if compromised.
Required scopes
crm.objects.contacts.read; crm.objects.contacts.write; crm.objects.deals.read; crm.objects.deals.write; crm.schemas.contacts.read; crm.schemas.deals.read; timeline (for activity logging)
Webhook / trigger setup
No inbound HubSpot webhook is required. HubSpot is a write target. If future bidirectional sync is added, use HubSpot webhooks with HMAC-SHA256 client secret validation.
Required configuration
HubSpot pipeline ID and stage IDs stored in the credential store with keys: HUBSPOT_PIPELINE_ID, HUBSPOT_STAGE_NEW_BOOKING, HUBSPOT_STAGE_DEPOSIT_PENDING, HUBSPOT_STAGE_CONFIRMED, HUBSPOT_STAGE_NO_SHOW. Custom property internal names for appointment_datetime and service_type must be confirmed during discovery and stored in config. Do not hardcode stage IDs or property names.
Rate limits
HubSpot Starter allows 100 API calls/10 seconds and 250,000 calls/day. At 120 bookings/month with up to 4 API calls per booking, peak usage is under 500 calls/day. No throttling required. Implement retry on 429 with 10-second backoff.
Constraints
Contact deduplication uses the email address as the primary identifier. The automation must call the contacts search endpoint before creating a new contact to avoid duplicates. Deal association to contact must be explicitly set in the deal create payload via associations array.
Stripe
Stripe generates a deposit payment link (Payment Link or Checkout Session) when a booking requires a deposit. Agent 2 listens for the checkout.session.completed or payment_intent.succeeded webhook event to confirm payment and update the booking status.
Auth method
Secret API key for server-side calls. Store as STRIPE_SECRET_KEY in the credential store. Webhook endpoint secret stored as STRIPE_WEBHOOK_SECRET. Never use the publishable key for server-side calls.
Required scopes
N/A for API key auth. If using Stripe Connect for multi-account, OAuth scopes apply (read_write on the connected account). For single-account use, the secret key grants full access; restrict key permissions to: Payment Links (write), Checkout Sessions (write), Payment Intents (read), Webhooks (read).
Webhook setup
Register the webhook endpoint in the Stripe Dashboard under Developers > Webhooks. Subscribe to events: checkout.session.completed; payment_intent.succeeded; payment_intent.payment_failed. Validate every inbound webhook by verifying the Stripe-Signature header using the STRIPE_WEBHOOK_SECRET and the Stripe SDK stripe.webhooks.constructEvent(). Reject unverified payloads with HTTP 400.
Required configuration
Stripe Price ID(s) for deposit amounts stored in the credential store as STRIPE_DEPOSIT_PRICE_ID (one per service type if amounts differ). Success and cancel redirect URLs stored in config. Deposit requirement flag per event type stored in config as a boolean keyed to the Calendly event type UUID.
Rate limits
Stripe allows 100 read requests/second and 100 write requests/second in live mode. At 120 bookings/month, no throttling is required. Implement exponential backoff on 429 and 503 responses with a maximum of 4 retries.
Constraints
Stripe operates in test mode and live mode independently. Test-mode keys (prefix sk_test_) must never be deployed to production. Payment Links expire only if an expiry is explicitly set; set a 48-hour expiry on all deposit links to prevent stale payments. PCI scope: the automation never handles raw card data; all card collection is on Stripe-hosted pages.
Twilio
Twilio sends SMS reminders at 48 hours and 2 hours before each confirmed appointment. Agent 3 calls the Twilio Messages API at the scheduled times. Delivery status is tracked via Twilio status callbacks.
Auth method
Account SID and Auth Token. Store as TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN in the credential store. Use HTTP Basic Auth (Account SID as username, Auth Token as password) on all API calls.
Required scopes
N/A (Twilio uses SID/token auth, not OAuth scopes). The sending number must be A2P 10DLC registered for US traffic. Store the registered sender number as TWILIO_FROM_NUMBER in the credential store.
Webhook setup
Set the StatusCallback URL on each message send request to the orchestration layer inbound webhook endpoint. The callback delivers MessageSid, MessageStatus (sent, delivered, failed, undelivered), and ErrorCode. Validate the callback authenticity using the X-Twilio-Signature header and the Twilio request validation library. Log all non-delivered statuses and trigger the Gmail email reminder as a fallback.
Required configuration
TWILIO_FROM_NUMBER stored in credential store. SMS template strings stored in config as TEMPLATE_SMS_REMINDER_48H and TEMPLATE_SMS_REMINDER_2H with tokens {{client_name}} and {{appointment_datetime}}. Reminder schedule offsets stored in config as REMINDER_OFFSET_HOURS_1=48 and REMINDER_OFFSET_HOURS_2=2 so they can be adjusted without a code change.
Rate limits
Twilio enforces a default throughput of 1 message/second per long code number for A2P traffic. At 120 bookings/month with 2 SMS per booking (240 SMS/month, approximately 8/day), throughput is well within limits. No throttling logic is required. If volume grows beyond 300 SMS/day, evaluate upgrading to a Twilio short code.
Constraints
A2P 10DLC registration is mandatory for US-based SMS at volume. Registration can take 1 to 4 weeks and must be completed before go-live. Opt-out compliance: every SMS must include STOP instructions per TCPA requirements. Store opt-out status in HubSpot and suppress Twilio sends for opted-out contacts. Do not send SMS to non-US numbers without verifying the applicable carrier and regulatory requirements for that country.
Integration and API SpecPage 2 of 4
FS-DOC-05Technical
03Field mappings between tools
The tables below define the exact field mappings at each agent handoff. Source and destination field names are shown in monospace format as they appear in the respective API payloads. All field names are case-sensitive.
Agent 1 handoff: Calendly to Google Calendar
Source tool
Source field
Destination tool
Destination field
Calendly
`event.name`
Google Calendar
`summary`
Calendly
`invitee.name`
Google Calendar
`summary` (prepended as client name)
Calendly
`event.start_time`
Google Calendar
`start.dateTime`
Calendly
`event.end_time`
Google Calendar
`end.dateTime`
Calendly
`invitee.email`
Google Calendar
`attendees[0].email`
Calendly
`invitee.text_reminder_number`
Google Calendar
`description` (appended as client phone)
Calendly
`event.location.join_url`
Google Calendar
`location`
Calendly
`event_type.uuid`
Google Calendar
`extendedProperties.private.calendly_event_type_uuid`
Agent 1 handoff: Calendly to Gmail (confirmation email)
Source tool
Source field
Destination tool
Destination field
Calendly
`invitee.email`
Gmail
`to`
Calendly
`invitee.name`
Gmail
`{{client_name}}` template token
Calendly
`event.start_time`
Gmail
`{{appointment_datetime}}` template token
Calendly
`event.name`
Gmail
`{{service_type}}` template token
Calendly
`event.location.join_url`
Gmail
`{{meeting_link}}` template token
Agent 2 handoff: Calendly booking record to HubSpot
Source tool
Source field
Destination tool
Destination field
Calendly
`invitee.email`
HubSpot
`properties.email`
Calendly
`invitee.name`
HubSpot
`properties.firstname` + `properties.lastname` (split on first space)
Calendly
`invitee.text_reminder_number`
HubSpot
`properties.phone`
Calendly
`event.start_time`
HubSpot
`properties.appointment_datetime` (custom property)
Calendly
`event.name`
HubSpot
`properties.service_type` (custom property)
Calendly
`event.uuid`
HubSpot
`properties.calendly_event_uuid` (custom property)
Orchestration
Deposit required flag (from config)
HubSpot
`properties.dealstage` = HUBSPOT_STAGE_DEPOSIT_PENDING or HUBSPOT_STAGE_CONFIRMED
Agent 2 handoff: Stripe to HubSpot (payment confirmation)
Source tool
Source field
Destination tool
Destination field
Stripe
`checkout.session.payment_status`
HubSpot
`properties.deposit_paid` (custom boolean property)
Stripe
`checkout.session.id`
HubSpot
`properties.stripe_session_id` (custom property)
Stripe
`checkout.session.amount_total`
HubSpot
`properties.deposit_amount_cents` (custom numeric property)
Stripe
`checkout.session.customer_email`
HubSpot
Used to look up existing contact by `email` before updating
Agent 3 handoff: HubSpot to Twilio and Gmail (reminders and no-show)
Source tool
Source field
Destination tool
Destination field
HubSpot
`properties.phone`
Twilio
`to` (E.164 format enforced)
HubSpot
`properties.firstname`
Twilio
`{{client_name}}` SMS template token
HubSpot
`properties.appointment_datetime`
Twilio
`{{appointment_datetime}}` SMS template token
HubSpot
`properties.email`
Gmail
`to`
HubSpot
`properties.firstname`
Gmail
`{{client_name}}` email template token
HubSpot
`properties.appointment_datetime`
Gmail
`{{appointment_datetime}}` email template token
HubSpot
`properties.service_type`
Gmail
`{{service_type}}` email template token
HubSpot
`id` (contact ID)
HubSpot
`properties.no_show_flagged` set to true on no-show update
Integration and API SpecPage 3 of 4
FS-DOC-05Technical
04Build stack and orchestration
Orchestration layout
Three discrete workflows, one per agent (Booking Intake Agent, CRM and Payment Agent, Reminder and Follow-Up Agent). Each workflow is independently deployable and testable. Shared state is passed between agents via a structured JSON payload written to the orchestration platform's internal data store at the end of each workflow. No direct agent-to-agent API calls; all inter-agent data is mediated through the shared store.
Credential store
All API keys, tokens, IDs, and template references are stored in the orchestration platform's encrypted credential/environment store. No credentials are hardcoded in workflow logic or template bodies. Credentials are referenced by key name only in workflow steps.
Agent 1 trigger (Booking Intake Agent)
Webhook (inbound). Calendly posts invitee.created and invitee.canceled events to a dedicated webhook endpoint on the orchestration layer. The endpoint validates the X-Calendly-Webhook-Signature header before any processing begins. Signature validation failure returns HTTP 401 and logs the rejection.
Agent 2 trigger (CRM and Payment Agent)
Webhook (inbound, dual source). Triggered either by Agent 1 completing and writing a booking record to the shared store (internal event trigger) or by a Stripe checkout.session.completed webhook arriving at a second dedicated endpoint. Stripe payloads are validated using the Stripe-Signature header before processing.
Agent 3 trigger (Reminder and Follow-Up Agent)
Scheduled poll + time-based execution. The orchestration layer polls the shared booking store every 15 minutes and evaluates each confirmed booking against the current UTC time. When a booking falls within the 48-hour or 2-hour reminder window, the reminder branch executes. For no-show detection, the workflow checks bookings where appointment_datetime is in the past by more than 30 minutes and the completion_status field is not set to completed. Poll interval is configurable via REMINDER_POLL_INTERVAL_MINUTES in the config store.
Environment separation
Maintain separate credential store entries for staging and production environments. Staging credentials reference Calendly test event types, Google Workspace test calendars, HubSpot sandbox (if available on plan), Stripe test-mode keys (sk_test_...), and Twilio trial numbers. Production promotion requires a deliberate credential swap in the store, not a code change.
Credential store contents (production keys, replace staging values before go-live):
Credential store: full key inventory (all values injected at runtime, never hardcoded)
# === Calendly ===
CALENDLY_CLIENT_ID=<oauth_client_id>
CALENDLY_CLIENT_SECRET=<oauth_client_secret>
CALENDLY_ACCESS_TOKEN=<rotating_access_token>
CALENDLY_REFRESH_TOKEN=<rotating_refresh_token>
CALENDLY_ORGANIZATION_URI=https://api.calendly.com/organizations/<uuid>
CALENDLY_WEBHOOK_SIGNING_KEY=<signing_key_from_subscription_create>
CALENDLY_EVENT_TYPE_UUID_DEFAULT=<primary_event_type_uuid>
# Add additional CALENDLY_EVENT_TYPE_UUID_<LABEL>=<uuid> for each appointment type
# === Google (Calendar + Gmail, shared OAuth app) ===
GOOGLE_CLIENT_ID=<oauth_client_id>
GOOGLE_CLIENT_SECRET=<oauth_client_secret>
GOOGLE_ACCESS_TOKEN=<rotating_access_token>
GOOGLE_REFRESH_TOKEN=<offline_refresh_token>
GOOGLE_CALENDAR_ID=<target_calendar_id>
GMAIL_FROM_ADDRESS=<sending_email_address>
GMAIL_FROM_NAME=<display_name>
GMAIL_REPLY_TO=<reply_to_address>
# === HubSpot ===
HUBSPOT_PRIVATE_APP_TOKEN=<private_app_bearer_token>
HUBSPOT_PIPELINE_ID=<deal_pipeline_id>
HUBSPOT_STAGE_NEW_BOOKING=<stage_id>
HUBSPOT_STAGE_DEPOSIT_PENDING=<stage_id>
HUBSPOT_STAGE_CONFIRMED=<stage_id>
HUBSPOT_STAGE_NO_SHOW=<stage_id>
# === Stripe ===
STRIPE_SECRET_KEY=sk_live_<key>
STRIPE_WEBHOOK_SECRET=whsec_<signing_secret>
STRIPE_DEPOSIT_PRICE_ID_DEFAULT=price_<default_deposit_price_id>
# Add STRIPE_DEPOSIT_PRICE_ID_<SERVICE>=price_<id> per service type
STRIPE_PAYMENT_LINK_EXPIRY_SECONDS=172800
STRIPE_SUCCESS_REDIRECT_URL=https://[YourCompany.com]/booking-confirmed
STRIPE_CANCEL_REDIRECT_URL=https://[YourCompany.com]/booking-cancelled
# === Twilio ===
TWILIO_ACCOUNT_SID=AC<account_sid>
TWILIO_AUTH_TOKEN=<auth_token>
TWILIO_FROM_NUMBER=+1<registered_a2p_number>
TWILIO_STATUS_CALLBACK_URL=https://<orchestration-host>/webhooks/twilio/status
# === Config (not secrets, but must not be hardcoded in workflow logic) ===
REMINDER_OFFSET_HOURS_1=48
REMINDER_OFFSET_HOURS_2=2
REMINDER_POLL_INTERVAL_MINUTES=15
NO_SHOW_DETECTION_GRACE_MINUTES=30
DEPOSIT_REQUIRED_EVENT_TYPES=<comma_separated_event_type_uuids>
TEMPLATE_CONFIRMATION=<template_key_or_html_ref>
TEMPLATE_DEPOSIT_REQUEST=<template_key_or_html_ref>
TEMPLATE_PAYMENT_CONFIRMED=<template_key_or_html_ref>
TEMPLATE_REMINDER_48H=<template_key_or_html_ref>
TEMPLATE_REMINDER_2H=<template_key_or_html_ref>
TEMPLATE_NO_SHOW=<template_key_or_html_ref>
TEMPLATE_SMS_REMINDER_48H=<sms_string_with_tokens>
TEMPLATE_SMS_REMINDER_2H=<sms_string_with_tokens>
Rotate STRIPE_SECRET_KEY, TWILIO_AUTH_TOKEN, and GOOGLE_REFRESH_TOKEN immediately if any are exposed in logs or error outputs. The orchestration platform must suppress credential values from all log outputs by marking them as secret-type variables.
05Error handling and retry logic
Every integration point has a defined failure behaviour. Unhandled exceptions must never fail silently. All errors are logged with a timestamp, the failing step name, the error code or message, and the booking record identifier. Where a human fallback is required, an alert is sent to the operations team via email to support@gofullspec.com or a configured internal notification channel.
Integration
Scenario
Required behaviour
Calendly webhook
Signature validation fails on inbound payload
Return HTTP 401. Log the rejection with raw header value (mask signing key). Do not process payload. Alert operations if more than 3 failures occur within 10 minutes (possible replay attack).
Calendly API
Access token expired (HTTP 401 on API call)
Automatically exchange CALENDLY_REFRESH_TOKEN for a new access token. Retry the original request once. If refresh also fails, log the error and halt the workflow; alert the FullSpec team via the monitoring channel.
Google Calendar
Event creation returns HTTP 409 (conflict / duplicate)
Query the calendar for the conflicting event using the time range. If the event already exists and the extendedProperties.private.calendly_event_type_uuid matches, treat as idempotent success. Otherwise log the conflict and alert operations.
Google Calendar
HTTP 429 rate limit exceeded
Apply exponential backoff: wait 2s, then 4s, then 8s. Retry up to 4 times. If all retries fail, log the error and queue the event creation for the next poll cycle. Do not drop the booking.
Gmail
Send fails with HTTP 5xx (Google server error)
Retry immediately once, then after 60 seconds, then after 5 minutes. After 3 failed attempts, log the failure and flag the booking record as email_send_failed. Do not re-send automatically after that point; require manual review.
Gmail
Template token substitution produces empty value (e.g. missing client name)
Substitute a safe fallback ('there' for {{client_name}}, 'your upcoming appointment' for {{service_type}}). Log the substitution with the booking ID and the missing field name for review. Do not block email delivery.
HubSpot
Contact deduplication finds multiple matches on email
Select the contact with the most recent createdate. Log the duplicate detection with all matching contact IDs. Do not create a new contact. Flag the record in HubSpot by setting a custom property duplicate_review=true for manual resolution.
HubSpot
HTTP 429 (API rate limit)
Queue the write operation and retry after 10 seconds. Apply exponential backoff up to 4 retries. If all retries fail, write the payload to a dead-letter log and alert operations. Do not silently drop CRM updates.
Stripe
Webhook signature validation fails
Return HTTP 400. Log the failure with the raw Stripe-Signature header value (do not log the signing secret). Do not update any booking status. If more than 5 validation failures occur in 1 hour, alert the FullSpec team.
Stripe
Payment link expires before client pays (48-hour expiry)
Do not automatically resend. Set the booking status to deposit_link_expired in HubSpot and send a single alert email to the operations team. A human decides whether to resend or cancel the booking.
Twilio
SMS delivery fails (status: failed or undelivered)
On receipt of the StatusCallback with a failed or undelivered status, immediately trigger the Gmail reminder email as a fallback for the same client and appointment. Log the Twilio ErrorCode and MessageSid. Do not retry the SMS.
Twilio
E.164 phone number format invalid
Validate phone number format before calling the Twilio API. If the stored number fails E.164 validation, skip the SMS send, flag the HubSpot contact with sms_invalid_number=true, and send only the Gmail reminder. Log the validation failure.
Orchestration layer
Unhandled exception in any workflow step
Catch all unhandled exceptions at the top-level error handler. Log the full stack trace, the workflow name, the step name, the booking ID, and a UTC timestamp. Send an immediate alert to the operations notification channel. Never allow a booking to be silently dropped or an agent to exit without a logged outcome.
Dead-letter queue: any booking payload that cannot be processed after all retries are exhausted must be written to a persistent dead-letter log with the full original payload, the error reason, and the booking ID. The FullSpec team reviews this log as part of the weekly monitoring cycle and during the first two weeks post-launch daily. Contact support@gofullspec.com to report a recurring failure pattern.
Integration and API SpecPage 4 of 4