{"type":"findusatime.system_agent_contract","version":"v1","name":"FindUsATime","purpose":"Create agent-native scheduling links for a human organizer.","primaryUserInstruction":"Give this URL to your AI agent: https://www.findusatime.com. Your agent can set up your organizer profile and create scheduling links.","baseUrl":"https://www.findusatime.com","humanBaseUrl":"https://www.findusatime.com","skill":"https://www.findusatime.com/skill.md","auth":"https://www.findusatime.com/auth.md","oauthProtectedResource":"https://www.findusatime.com/.well-known/oauth-protected-resource","oauthAuthorizationServer":"https://www.findusatime.com/.well-known/oauth-authorization-server","openapi":"https://www.findusatime.com/openapi.json","lifecycle":["discover_system","ensure_organizer_exists","collect_or_derive_organizer_availability","create_meeting_link","send_link_to_invitee","invitee_completes_booking"],"agentFirstOnboarding":{"entryInstruction":"If the user gives you https://www.findusatime.com and asks you to set up scheduling, fetch /skill.md first, then fetch /.well-known/agent.json and follow this onboarding flow.","optimizedFor":"OpenClaw-style personal agents that already know the user's display name, email, timezone, and can request permission to read calendar availability and send email.","recommendedFlow":["Reuse known user profile fields for displayName, email, and timezone when available.","Ask permission to create a public FindUsATime scheduling username. Explain that this is not an account, has no password, and creates no login credential.","Ask the user for a preferred public username, or suggest URL-safe options and ask the user to approve one.","Create the restricted organizer with POST /agent/organizers, then store the returned username for reuse.","Ask the human to open the returned claimUrl before requesting durable API credentials or reporting calendar writes.","For each meeting request, collect or infer recipient, duration, and an explicit scheduling window.","Ask permission to read the organizer's calendar for that specific request, then derive 3-10 free blocks as organizerAvailability.","Create the meeting with POST /agent/meetings using organizerUsername and organizerAvailability, or use the single-call path with an embedded organizer object.","Send data.meetingUrl to a human recipient, or data.agentUrl to a recipient's AI agent."],"knownProfileFieldsToReuse":["displayName","email","timezone"],"askUserFor":["permission to create a public scheduling username","preferred username or approval of a suggested username","recipient name or email","meeting duration","requested date/window if not already specified","permission to read calendar availability for the requested window","permission to send the scheduling link"],"doNotAskFor":["password","login credentials","API key unless the user explicitly asks for programmatic API access","full calendar export"],"permissionsToAsk":[{"permission":"create_public_username","reason":"The username appears in public scheduling links."},{"permission":"read_calendar_availability","reason":"Organizer availability is required to create useful meeting links."},{"permission":"send_scheduling_link","reason":"FindUsATime does not send email itself; the agent should send the returned link if the user approves."}],"usernamePolicy":{"format":"2-30 characters, lowercase letters, numbers, and internal hyphens only","agentInstruction":"Do not silently choose the final username. Ask the user to approve it before creating the organizer."},"singleCallPath":{"method":"POST","url":"/agent/meetings","description":"Agents may create the organizer and meeting in one request by including organizer: { displayName, email, timezone, username } plus meeting details.","requiredInputs":["organizer","durationMinutes","window","inviteeName","organizerAvailability"]}},"actions":{"createOrganizer":{"method":"POST","url":"/agent/organizers","requiredInputs":["displayName","email","timezone","username"],"guidance":"Creates a restricted public scheduling identity for the organizer - analogous to a Calendly URL slug. This is NOT a full account: there is no password and no usable API credential until the human opens the returned claimUrl. The username is a URL slug; the email is used as the ICS ORGANIZER address on confirmed meetings; the timezone is used to interpret scheduling windows. Ask the user to choose a username - it appears in public scheduling links."},"getOrganizerProfile":{"method":"GET","urlTemplate":"/users/{username}/agent"},"createMeeting":{"method":"POST","url":"/agent/meetings","requiredInputs":["organizerUsername","durationMinutes","window","inviteeName","organizerAvailability"],"optionalInputs":["inviteeUsername"],"guidance":"Use inviteeUsername instead of inviteeName when the invitee is a known FindUsATime user and their agent will authenticate brokered calendar-write confirmation."},"respondToMeeting":{"method":"POST","url":"/agent/respond"},"refreshOrganizerAvailability":{"method":"POST","url":"/agent/organizer-availability","requiredInputs":["token"],"optionalInputs":["organizerAvailability","availability","timezone"],"guidance":"After an invitee submits availability, the organizer agent should re-check the organizer's current calendar and submit refreshed free blocks here before confirming a proposed time."},"confirmMeeting":{"method":"POST","url":"/agent/confirm"},"reportCalendarWrite":{"method":"POST","url":"/agent/calendar-writes","requiredInputs":["token","participantKey","status","calendarProvider"],"requiredHeaders":["Authorization: Bearer <apiKey>","Idempotency-Key"],"optionalInputs":["externalEventId","failureCode","failureMessage"],"guidance":"Gold-path calendar completion is reached only after both organizer and invitee agents report confirmed writes to their own user's calendar. The authenticated user must match the participant role being reported."},"getBrokeredStatus":{"method":"GET","urlTemplate":"/agent/status/{token}"},"resolvePollingCycle":{"method":"POST","url":"/agent/polling-cycle","requiredInputs":["token","action"],"actionValues":["continue_24h","delete_request"]}},"hybridBrokeredProtocol":{"mode":"gold_path","coordinatorRole":"FindUsATime tracks negotiation state and calendar-write confirmations, while each agent keeps custody of its own user's calendar credentials.","completionState":"CALENDAR_WRITES_CONFIRMED","writeConfirmationRequiredFrom":["organizer","invitee"],"reportCalendarWrite":{"method":"POST","url":"/agent/calendar-writes","requiredInputs":["token","participantKey","status","calendarProvider"],"requiredHeaders":["Authorization: Bearer <apiKey>","Idempotency-Key"],"confirmedInputs":["externalEventId"],"failedInputs":["failureCode","failureMessage"]},"pollStatus":{"method":"GET","urlTemplate":"/agent/status/{token}"},"fallback":"ICS remains available through /meet/{token}/ics, but ICS delivery alone is not treated as gold-path success."},"organizerAvailabilityRequirement":{"field":"organizerAvailability","required":true,"rules":["Do NOT assume full availability","Ask organizer what days/times to offer","OR ask permission to read calendar and derive availability"]},"organizerIdentity":{"type":"public_scheduling_identity","isAccount":false,"hasPassword":false,"hasLoginCredential":false,"storedFields":["username (public URL slug)","displayName","email (used as ICS ORGANIZER)","timezone"],"analogousTo":"A Calendly URL handle. The username is a public slug; the email and timezone are identity metadata for generating shareable scheduling links and rendering calendar invites.","note":"Agents may create an organizer on the user's behalf without triggering account-creation safeguards. No credentials are issued, stored, or required."},"windowRequirement":{"type":"object","fields":["start","end"],"format":"ISO datetime","note":"Agents must convert natural language (e.g. 'next week') into explicit datetime ranges before calling the API."},"timeRequirement":{"mustBeFuture":true,"note":"All meeting windows must be in the future. Agents should generate time ranges relative to the current date."},"calendarFallbackPolicy":{"strategy":"ask_permission_then_derive","contextPriorityRule":"If organizer provides timing context (e.g. next week, Friday afternoon, tomorrow morning), use that context FIRST.","defaultRule":"Only apply default lookahead when organizer provides no timing context.","defaultLookaheadDays":3,"expandedLookaheadDays":5,"expansionCondition":"Expand to 5 days only if insufficient availability or no overlap later.","slotConstraints":{"recommendedBlocks":"3-10","maxBlocks":20},"recommendedBlocks":"3-10","maxBlocks":20,"permissionRequired":true,"note":"Slots represent curated candidate meeting options, not full calendar availability."},"agentResponsibilities":["discover this contract","collect user identity","create organizer","store username for reuse","collect or derive organizerAvailability","create meeting links via /agent/meetings","send meetingUrl or agentUrl to invitee"],"safety":{"calendarAccessRequired":false,"externalCalendarModified":false,"note":"Agents must ask permission before reading user calendar. Confirmed meetings return ICS content.","rules":["agents must request permission before reading user calendar","creating an organizer is not account creation - no password, no login, no stored credential","confirmed meetings return ICS content/link"]},"endpoints":{"respond":{"method":"POST","path":"/agent/respond","description":"Availability submission endpoint with proposed meeting time response","input":{"token":"string","name":"string","timezone":"string","inviteeEmail":"required email string for calendar_invite_delivery; if omitted, /agent/respond returns nextAction=require_invitee_email","mode":"optional, 'minimal'","availability":"optional array of free blocks: [{ start: ISO datetime, end: ISO datetime }]"}},"confirm":{"method":"POST","path":"/agent/confirm","description":"Meeting confirmation endpoint for a proposed meeting time. Response includes inline calendarEvent.content in ICS format so agents can deliver it to the invitee as a clickable/openable file.","input":{"token":"string","inviteeEmail":"required email string for calendar_invite_delivery unless already supplied to /agent/respond"},"output":{"ok":true,"version":"v1","state":"CONFIRMED for anonymous or ICS-fallback flows; AWAITING_CALENDAR_WRITES for authenticated brokered two-user flows","data":{"meetingStatus":"confirmed","confirmedStart":"ISO datetime","confirmedEnd":"ISO datetime","calendarEvent":{"format":"ics","downloadUrl":"string","content":"full ICS calendar content"},"brokeredProtocol":{"mode":"hybrid_brokered","state":"AWAITING_CALENDAR_WRITES until both authenticated participants report confirmed calendar writes","reportCalendarWrite":"POST /agent/calendar-writes next action","pollStatus":"GET /agent/status/:token next action"}},"missingFields":[],"goalStillActive":"false for CONFIRMED fallback; true for AWAITING_CALENDAR_WRITES brokered flow","nextAction":"add_to_calendar for fallback flows; report_calendar_write for brokered flows"}},"reportCalendarWrite":{"method":"POST","path":"/agent/calendar-writes","description":"Hybrid brokered gold-path endpoint. Each agent reports whether it wrote and verified the final event on its own user's calendar.","input":{"token":"string","participantKey":"'organizer' | 'invitee'","status":"'confirmed' | 'failed'","calendarProvider":"provider key such as google_calendar","authorization":"required Authorization header: Bearer <participant api key>","idempotencyKey":"required Idempotency-Key header; safe retries must reuse the same key with the same payload","externalEventId":"required when status is confirmed","failureCode":"required when status is failed","failureMessage":"optional human-readable failure detail"},"successState":"CALENDAR_WRITES_CONFIRMED after both participants report status=confirmed"},"brokeredStatus":{"method":"GET","path":"/agent/status/:token","description":"Polls the brokered negotiation state, including organizer/invitee calendar-write confirmation status.","outputStates":["AWAITING_AVAILABILITY","ORGANIZER_RECHECK_REQUIRED","PROPOSED_TIME","AWAITING_CALENDAR_WRITES","CALENDAR_WRITES_CONFIRMED","CALENDAR_WRITE_FAILED","REQUEST_DELETED"]},"createMeeting":{"method":"POST","path":"/agent/meetings","description":"Meeting link creation endpoint. Agents may include an organizer object for automatic onboarding, or pass organizerId/organizerUsername for an existing organizer. organizerAvailability is required for the agent-native happy path.","input":{"organizerId":"optional string for an existing organizer","organizerUsername":"optional string for an existing organizer","organizer":"optional object: { displayName, email, timezone, username } for automatic onboarding","inviteeUsername":"optional string for an existing invitee user; required for authenticated brokered calendar-write reporting by the invitee","durationMinutes":"15 | 30 | 60","window":{"type":"object","fields":["start","end"],"format":"ISO datetime","note":"Natural language windows are not accepted. Convert timing phrases into explicit start/end datetimes before calling this endpoint."},"inviteeName":"string","organizerAvailability":"Required array of organizer free-time blocks for agent-native scheduling. Agents should ask the organizer what days/times to offer, or ask permission to read the organizer's calendar and derive availability before creating a meeting."},"calendarFallbackPolicy":{"strategy":"ask_permission_then_derive","contextPriorityRule":"If organizer provides timing context (e.g. next week, Friday afternoon, tomorrow morning), use that context FIRST.","defaultRule":"Only apply default lookahead when organizer provides no timing context.","defaultLookaheadDays":3,"expandedLookaheadDays":5,"expansionCondition":"Expand to 5 days only if insufficient availability or no overlap later.","slotConstraints":{"recommendedBlocks":"3-10","maxBlocks":20},"recommendedBlocks":"3-10","maxBlocks":20,"permissionRequired":true,"note":"Slots represent curated candidate meeting options, not full calendar availability."},"output":{"ok":true,"version":"v1","state":"AWAITING_AVAILABILITY","data":{"token":"string","meetingUrl":"absolute human meeting URL","agentUrl":"absolute invitee-agent contract URL","organizer":"{ username, displayName, email, timezone }","schedulingEnvelope":"findusatime.scheduling_request envelope, version v1, intended for agent-to-agent delivery such as embedding in an email"},"missingFields":[],"goalStillActive":true,"nextAction":"{ type: 'send_link_to_invitee', url: string, method: 'GET' }"}},"createOrganizer":{"method":"POST","path":"/agent/organizers","description":"Creates a restricted public scheduling identity for the organizer (NOT a full account - no password and no usable API credential until the human opens claimUrl; analogous to a Calendly URL slug). Agents should ask the user for display name, email, timezone, and a preferred public username. The username appears in public scheduling links; the email is used as the ICS ORGANIZER on confirmed meetings; the timezone is used to interpret scheduling windows.","input":{"displayName":"string","email":"string","timezone":"string","username":"required public URL slug, 2-30 chars: lowercase letters, numbers, internal hyphens"},"errors":{"username_required":"Username is required; response includes suggestions.","username_unavailable":"Username is unavailable; response includes suggestions."}},"agentContract":{"method":"GET","path":"/meet/:token/agent","description":"OneCall contract for this meeting"},"calendarInvite":{"method":"GET","path":"/meet/:token/ics","description":"Download a confirmed meeting as a standard ICS calendar file"},"organizerIdentity":{"requiredFields":["id","username","displayName","email","timezone"],"emailPurpose":"ICS ORGANIZER identity","usernamePurpose":"Public URL slug for scheduling links. Agents should ask the user to choose it."},"organizerIdentityStrategy":{"preferred":"include organizer object in /agent/meetings for automatic onboarding","alternative":"use POST /agent/organizers explicitly","note":"agents may choose either path"},"compatibilityTest":{"method":"GET","path":"/agent/test","description":"Deterministic compatibility request for agent verification"}}}