Home-service operating guide
AI phone agent scheduling integrations: test the record before confirming the booking
Your AI phone agent can hear a preferred time, find an opening and still leave the office with an incorrect appointment. A request might reach the wrong branch, a write might succeed after the connection times out, or an employee might change the appointment while the agent is preparing an update.
Updated · Published by Revo
A centralized scheduling integration needs an acceptance test for those record-level failures. Start with one question: What authoritative record must exist before the caller hears “confirmed”?
This guide provides a proposed state model, integration contract and synthetic failure pack for a selected connection. These are design and testing materials, not a working Revo integration or evidence that Revo supports a named calendar. Google Calendar supplies documented technical examples; it does not establish field-service capacity rules or a Revo-native connection. Documentation reviewed October 23, 2026.
1. Put the authoritative record inside the boundary
Name the destination that owns the appointment or job. If a field-service system owns dispatch capacity and a separate calendar mirrors it, a calendar event alone cannot satisfy your acceptance rule. Document which system wins when they disagree.
Carry these identifiers through intake, writes, retries and exceptions:
- An immutable request ID for the caller’s requested operation.
- The authoritative customer and service-location IDs, rather than name-only matching.
- The branch and destination calendar IDs selected from an approved mapping.
- The appointment or job ID returned by, or validly assigned for, the destination.
- The requested local time, IANA time zone and explicit UTC offset.
- The version read before changing an existing record.
The request ID ties attempts together. It does not prove the caller’s identity, reserve a time slot or make a second customer’s competing request disappear. Store only the information necessary for the operation and keep credentials out of transcripts and diagnostic bundles.
2. Use a state model with an uncertainty branch
The following is a proposed application model. Names are internal states, not Google Calendar API statuses.
REQUESTED
| validate identity, branch, operation and permissions
v
ELIGIBILITY_CHECKED
| inspect every required availability result
v
AVAILABILITY_OBSERVED
| record operation ID and intended payload before sending
v
WRITE_PENDING ------------------- timeout ----------------> WRITE_UNCERTAIN
| successful write response |
v | reconcile by stable ID
PERSISTED_RECORD_INSPECTED <------------------------------------+
| exact destination, customer/location, time and operation verified
| no newer cancellation or superseding request
v
CONFIRMED
Validation failure, incomplete availability, stale version,
unresolved write, or mismatched persisted record -> EXCEPTION_OWNED
Cancellation requested while WRITE_PENDING or WRITE_UNCERTAIN:
record cancellation intent -> suppress booking confirmation -> reconcile write
-> authorized cancellation -> verify destination state -> CANCELLED
|
+-> failure -> EXCEPTION_OWNED
Do not silently move from WRITE_UNCERTAIN back to a fresh insertion. Inspect the original destination and operation identity first. If reconciliation remains inconclusive, leave a named exception owner and tell the caller the office must verify the request.
In Google Calendar, a free/busy query returns availability information for specified calendars. Its response can contain errors for individual calendars. Inspect those entries even when the overall request returns successfully. A missing or errored calendar must not become an empty busy list in your application. The query supplies information, not a reservation. Google Calendar free/busy reference
3. Define the contract before choosing credentials
Use this proposed contract as a reviewable CSV. The owner column identifies who resolves a mismatch, not who receives every notification. Replace the synthetic values with authorized test identifiers before exercising a real connection.
field,source_of_truth,example,validation,expected_write,exception_owner
request_id,intake operation ledger,req-001,immutable across retries,operation ledger only,integration lead
customer_id,customer system,cust-001,unique authorized match,reference on destination,office scheduler
location_id,service-location system,loc-001,belongs to customer,reference on destination,office scheduler
branch_id,approved routing map,branch-east,maps to permitted calendar,branch reference,branch administrator
calendar_id,destination configuration,cal-east,exact authorized branch mapping,target resource,integration lead
time_zone,branch configuration,America/New_York,local time and offset agree,event time zone,office scheduler
start,caller-approved request,2026-11-02T09:00:00-05:00,round-trip local time is identical,event start,office scheduler
end,approved duration rule,2026-11-02T10:00:00-05:00,after start and approved duration,event end,office scheduler
record_id,destination or supported ID allocator,event-001,stable reconciliation reference,one intended record,integration lead
expected_version,last authoritative read,v1,matches current version before edit,conditional change,integration lead
permissions,authorized access configuration,event read and write,operation allowed on target calendar,no permission escalation,account administrator
operation,caller-approved operation,create,create or change or cancel,only intended mutation,office scheduler
exception_owner,approved operations roster,office-scheduler-east,assigned before testing,exception queue record,operations manager
The sample record_id is an illustrative application value, not a claim that its format is valid for every API. Follow the destination’s identifier rules. Preserve the external record ID and operation ID separately when they differ.
Separate availability access from mutation access
| Test requirement | Google Calendar example | Contract question |
|---|---|---|
| Inspect availability | calendar.events.freebusy covers availability on accessible calendars | Which exact calendars may this identity inspect? |
| Read event details | calendar.events.readonly | Can the integration locate and verify the intended record? |
| Create, change and delete events | calendar.events.owned applies to owned calendars; other configurations require their appropriate scope | Does the authorized identity have the required operation on this destination? |
| Change sharing or calendar configuration | Separate ACL/calendar scopes exist | Why would a booking connection need this administrative power? |
Google recommends the narrowest scopes that meet the application’s requirements. Its permission model is an example, not a portable permission specification for every scheduling product. Do not request account-wide administration merely to resolve a failed booking test. Google Calendar authorization scopes
4. Test three different concurrency problems
One request delivered twice. Keep the same operation identity and reconcile an existing result. If the destination supports client-assigned identifiers, follow its collision rules. A duplicate-identifier response requires inspection of the existing record, not an automatic new identifier that creates another appointment.
Two customers choosing the same opening. Their request IDs are different. Both might observe free time before either writes. Your authoritative scheduling system needs its own supported capacity-control mechanism. A stable request ID alone offers no protection against this race; a bare read/write calendar pair does not guarantee exclusive booking.
An employee editing an existing appointment. Read its version, submit a conditional modification and resolve changes rather than overwriting them blindly. Google Calendar supports If-Match with the previously read etag for update/delete operations. A changed resource produces HTTP 412. Conditional insertion is different: the documented insert safeguard concerns an existing resource ID, not two events occupying the same time. Google Calendar resource versioning
5. Give each failure a bounded recovery path
| Failure | Proposed application behavior |
|---|---|
| Invalid payload | Correct the input; do not loop on the same invalid request. |
| Missing authorization or access | Stop that operation and route to the authorized administrator; never broaden credentials automatically. |
| Duplicate identifier | Inspect the existing record and compare the intended operation before deciding whether it is the same result. |
| Stale record version | Read the current record and resolve the competing change; do not blindly overwrite it. |
| Rate limiting | Use the platform’s documented backoff guidance with an explicit attempt/time budget and exception owner. |
| Write timeout | Treat persistence as unknown; reconcile before any retry that could create another record. |
| Cancellation failure | Keep cancellation pending until the authoritative destination supplies sufficient evidence of the intended state. |
Google documents invalid-request errors, duplicate IDs, stale-version failures, and rate-limit responses including 403/429. Error reasons matter alongside HTTP status; a 403 is not always the same problem. Its guidance includes exponential backoff for retryable failures. Set a bounded application policy rather than promising indefinite recovery. The uncertainty handling above is a proposed design, not a claim that a timeout proves success or failure. Google Calendar error handling
6. Run the synthetic failure fixtures
Use invented customers and a provider-supported test environment. The companion local fixture runner models the acceptance rules without network access or credentials. It tests a deliberately small reference model, not a live connector, API compliance, or production concurrency. The model uses one synthetic east branch and rejects stale updates; successful appointment changes are intentionally unsupported rather than simulated as verified writes. An integration team must replay equivalent failures against its authorized adapter before signing off.
| Fixture and injected condition | Expected authoritative result | Caller wording | Owner and required evidence |
|---|---|---|---|
Duplicate request: deliver req-001 twice | One intended record; both deliveries resolve to its ID | “Your appointment is confirmed” only after verification | Integration lead: request-to-record mapping and record count |
| Wrong branch: route east request to west calendar | No new record | “The office needs to verify the location before confirming” | Branch administrator: approved map and rejected target |
| Partial availability: one required calendar returns an error | No new record | “I cannot verify that opening yet” | Integration lead: per-calendar response and exception ID |
| Calendar unavailable: destination lookup cannot complete | No new record or assumed availability | “The office must verify availability” | Integration lead: lookup failure and retry/exception decision |
| Local-time mismatch: New York November time supplied with the wrong offset | No new record | “Let’s verify the local time before confirming” | Scheduler: local time, zone, offset and conversion |
| Stale update: employee edits version 1 into version 2 before agent writes | Employee’s version preserved; change remains unresolved | “Your requested change is pending review” | Scheduler: both versions and rejected conditional update |
| Write timeout after persistence | Original record recovered; no second record | Confirmation only after inspection of that record | Integration lead: original operation ID, timeout and read-back |
| Write timeout before persistence, reconciliation unavailable | No confirmation and no speculative replacement write | “Your request is awaiting verification” | Integration lead: uncertainty state and assigned exception |
| Cancellation during pending creation, then failed cancellation | Persisted record remains active; cancellation stays pending; booking confirmation suppressed | “Your cancellation request is pending verification” | Scheduler: cancellation intent, resulting record and failure |
For a successful cancellation, replace the injected failure with a verified terminal result and assert that no active booking remains. A not-found response by itself may reflect access or lookup problems; use the destination’s documented behavior and your identity checks before treating it as cancellation evidence.
Run the supplied offline file with python centralized-scheduling-fixtures.py using a Python installation with IANA time-zone data. Passing assertions establish only that this small reference model meets its fixtures; they do not certify your selected connector.
7. Accept the connection only with evidence
Require an operation log that connects the input, authorized destination, attempted mutation, inspected result, customer message and exception owner. Mask personal data in review copies. Reject a test that passes only because the system sends reassuring language while the destination is unknown.
Stop testing and disable the affected mutation path if it writes to an unintended branch, loses a competing edit or duplicates a request. Preserve evidence and reconcile affected records through an authorized operator; do not run a bulk-delete “rollback” against live calendars.
Next step: establish what your office means by a requested versus confirmed appointment in the appointment-booking guide, then give this record contract to the team implementing your chosen connection. For platform-specific evaluation, use the Jobber answering-service guide or ServiceTitan answering-service guide. These links are buying-context resources, not proof that any particular integration passes these tests.
Companion resources
7. Accept the connection only with evidence
Review Revo’s current features and plans for the workflow your business needs.
Compare plans