Human‑Centric Availability Resolution
Calendario is a federated, identity‑first protocol for resolving a person’s availability. It enables apps, assistants, agents, and software to determine when, how, and under what conditions a human is available — by resolving a structured JSON profile located at:
/.well‑known/calendario/{username}
The protocol only standardizes how a person or organization declares their:
Calendario is designed to be:
GET https://yourdomain.com/.well-known/calendario/jane
Accept: application/json
Schema Compliance
The JSON profile must conform to calendario-schema-v0.1.json
and can be validated using validator.py
.
{
"version": "0.1",
"username": "jane",
"display_name": "Jane Doe",
"self": "did:key:xyz...",
"self_proof": {
"type": "DIDSignature2021",
"created": "2025-05-03T17:00:00Z",
"proofPurpose": "assertionMethod",
"verificationMethod": "did:key:xyz...",
"jws": "eyJhbGciOiJFUz..."
},
"organization": "https://acme.example.com",
"organization_proof": {
"type": "DIDSignature2021",
"created": "2025-05-03T18:00:00Z",
"proofPurpose": "assertionMethod",
"verificationMethod": "did:key:abc123...",
"jws": "eyJhbGciOiJFUz..."
},
"representing": "ceo@acme.example.com",
"representing_proof": {
"type": "DIDSignature2021",
"created": "2025-05-03T17:30:00Z",
"proofPurpose": "assertionMethod",
"verificationMethod": "did:key:xyz123...",
"jws": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9..."
},
"timezone": "America/New_York",
"visibility": "public",
"allow_anonymous_booking": false,
"min_notice_hours": 72,
"max_bookings_per_day": 3,
"blackouts": [
"2025-12-01",
{ "start": "2025-12-24", "end": "2025-12-31" }
],
"scheduling": [
{
"type": "weekly",
"days": ["monday", "wednesday", "friday"],
"hours": ["09:00-11:00", "16:00-18:00"],
"expires": "2025-06-30"
},
{
"type": "date",
"dates": ["2025-06-07", "2025-06-10"],
"hours": ["09:00-11:00"]
},
{
"type": "range",
"start": "2025-06-01",
"end": "2025-06-14",
"days": ["monday", "tuesday", "thursday"],
"hours": ["17:00-20:00"]
}
],
"pricing": {
"hour": 75,
"half_hour": 45,
"currency": "USD"
},
"payment_required": true,
"payment_url": "https://yourdomain.com/pay/jane",
"no_show_policy_url": "https://yourdomain.com/no-show",
"terms_url": "https://yourdomain.com/terms",
"privacy_url": "https://yourdomain.com/privacy",
"response_channel": {
"human_ack_required": true,
"notify": [
{ "type": "email", "value": "jane@example.com" },
{ "type": "sms", "value": "+14155551234" },
{ "type": "push", "value": "https://push.jane.dev/inbox" },
{ "type": "webhook", "value": "https://jane.dev/notify" },
{ "type": "matrix_dm", "value": "@jane:matrix.org" }
],
"confirm": {
"meeting_response_url": "https://yourdomain.com/api/bookings/jane",
"static_meeting_url": "https://meet.google.com/abc-defg-hij",
"free_busy_url": "https://yourdomain.com/api/freebusy/jane"
},
"booking_confirmation_message": "Thank you for booking with Jane. Please bring your brief and join the call 5 mins early.",
"booking_error_message": "Sorry, I'm no longer available at this time. Please propose another slot."
}
}
Field | Type | Required | Description | Example / Context |
---|---|---|---|---|
version | string | ✅ | Protocol version used | "0.1" — allows future breaking changes |
username | string | ✅ | Username component of URL | "jane" |
display_name | string | ✅ | Human‑readable name | "Jane Doe" |
self | string | ✅ | DID or unique self‑identifier | "did:key:xyz..." |
self_proof | object | ✅ | Signature proving identity ownership | JSON‑LD proof with JWS |
organization | string | — | URL of affiliated organization | "https://acme.example.com" |
organization_proof | object | — | Proof signed by org key | Org DID signature |
representing | string | — | Email/DID you act on behalf of | "ceo@acme.example.com" |
representing_proof | object | — | Signature authorizing representation | JWS |
timezone | string | ✅ | IANA time zone | "America/New_York" |
visibility | string | ✅ | "public" or "private" profile | "public" |
allow_anonymous_booking | boolean | ✅ | Permit unauthenticated bookings | false |
min_notice_hours | integer | — | Required notice period | 72 |
max_bookings_per_day | integer | — | Daily booking limit | 3 |
blackouts | array | — | Specific unavailable dates/ranges | ["2025‑12‑01", {start,end}] |
scheduling | array | ✅ | Availability blocks | See Scheduling Blocks |
pricing | object | — | Rates & currency | {"hour":75} |
payment_required | boolean | — | Is pre‑payment mandatory? | true |
payment_url | string | — | URL to pay | Stripe link |
no_show_policy_url | string | — | Cancellation / no‑show policy | Policy page |
terms_url | string | — | Engagement terms | Terms page |
privacy_url | string | — | Privacy policy | Privacy page |
response_channel | object | ✅ | Notification & confirmation config | See Response Channel |
meta | object | — | Arbitrary tags / hints | {"x-tags":["founder"]} |
Each item in scheduling
defines availability logic.
{
"type": "weekly",
"days": ["monday", "wednesday"],
"hours": ["09:00-12:00"],
"expires": "2025-06-30"
}
Types supported:
"response_channel": {
"human_ack_required": true,
"notify": [ ... ],
"confirm": { ... },
"booking_confirmation_message": "...",
"booking_error_message": "..."
}
notify
— multiple channels (email, sms, push, webhook, matrix_dm)confirm.meeting_response_url
— POST here to bookconfirm.static_meeting_url
— fallback meeting linkconfirm.free_busy_url
— GET here to check live conflictsPOST to meeting_response_url
:
{
"status": "confirmed",
"meeting_url": "https://meet.google.com/xyz-1234",
"start_time": "2025-06-03T14:00:00Z",
"duration_minutes": 30,
"confirmation_message": "Looking forward to speaking with you!"
}
If time is unavailable:
{
"status": "conflict",
"reason": "Requested time already booked",
"suggested_times": ["2025-06-03T15:00:00Z"],
"fallback_meeting_url": "https://meet.google.com/xyz-9999"
}
{
"busy": [
{ "start": "2025-06-03T14:00:00Z", "end": "2025-06-03T14:30:00Z" }
],
"generated_at": "2025-05-03T16:00:00Z",
"ttl_seconds": 300
}
Clients should call this before POSTing to avoid conflicts.
self_proof
and organization_proof
with verifiable signatures..well-known/calendario
endpoints.free_busy_url
to check conflicts before booking.min_notice_hours
and max_bookings_per_day
.meeting_response_url
with atomic checks.visibility
, payment_required
, and blackouts
.Clients MUST ignore unknown top‑level fields. Arbitrary additions belong in meta
or should start with x‑
.
Add this TXT record to DNS:
calendario=/.well-known/calendario
Calendario Protocol is open‑source under the MIT License. Anyone can adopt, implement, or extend it.