Skip to content
Rigel docs
Open Rigel

Create or update the event an app's record owns

calendar.source_event.put

POST/api/v1/households/{household_id}/commands/calendar.source_event.put

  • Command
  • Rigel runs it
  • Applies offline

For other apps and HTTP callers: keeps one event for (source_app, source_record_id). The input says how the event is now; anything left out goes back to its default, except person_ids and reminders, which are only replaced when given. calendar_id is used only when the event is made. The event can't be edited through the calendar's own commands (event_owned_by_app) except to move it, attach files, or set its people and reminders. Errors: calendar_not_found, person_not_found, invalid_time_range, invalid_recurrence.

Parameters#

Create or update the event an app's record owns: parameters
FieldDescription
household_idpathstringrequired

The household's ID.

Idempotency-Keyheaderstringoptional

The command's ID. Reuse it when retrying the same command.

Request body#

JSON, as application/json.

Create or update the event an app's record owns: request body fields
FieldDescription
source_appone of: meals, recipes, shopping, inventory, email, tasks, documents, chat, maintenancerequired

The app that owns the event: any app but calendar.

source_record_idstringrequired

The ID of the app's own record that this event shows.

1 to 200 characters
calendar_idstringoptional

Used only when the event is made; after that it stays where people moved it. Defaults to the default calendar.

titlestringrequired

The event's title, as written, 1–200 characters.

1 to 200 characters
descriptionstring or nulloptional

Notes about the event, as written, up to 8,000 characters.

at most 8,000 characters
locationstring or nulloptional

Where it is, as written, up to 500 characters.

at most 500 characters
kindone of: event, appointment, activity, chore, meal, trip, birthday, holiday, reminder, busyoptional

What sort of thing it is: event (the default), appointment (a doctor, a contractor), activity (swim, practice), chore, meal, trip, birthday, holiday, reminder, or busy (time blocked with no details).

statusone of: confirmed, tentativeoptional

confirmed (the default), or tentative for a plan that isn't settled.

starts_atstringoptional

When a timed event starts. ISO 8601: with an offset it's that instant, without one it's wall-clock time in time_zone, so 2026-11-11T15:30 means 3:30pm there.

ends_atstringoptional

When a timed event ends, in the same form as starts_at.

start_datestringoptional

The first day of an all-day event, YYYY-MM-DD.

end_datestringoptional

The last day of an all-day event, YYYY-MM-DD, inclusive. The same as start_date for a one-day event.

time_zonestringoptional

The IANA zone the event happens in, such as America/New_York. Defaults to the household's zone.

recurrencestring or nulloptional

An RFC 5545 repeat rule without the "RRULE:" prefix, such as FREQ=WEEKLY;BYDAY=SA;UNTIL=20270328. Supports FREQ DAILY, WEEKLY, MONTHLY and YEARLY with INTERVAL, COUNT, UNTIL, BYDAY (with positions), BYMONTHDAY, BYMONTH, BYSETPOS and WKST.

1 to 500 characters
person_idsarray of stringsoptional

The family members the event involves. Duplicates are ignored.

at most 50 items
remindersarray of objectsoptional

Reminders before the event or each occurrence, at most 5. Replaces the event's current reminders.

at most 5 items
reminders[].minutes_beforeintegerrequired

How long before the event starts, 0 to 40,320 (4 weeks).

0 to 40,320
reminders[].person_idstring or nulloptional

Who to remind. Leave out or null for the people on the event (or the calendar's owner, or everyone).

Response#

200 The command was applied.

Create or update the event an app's record owns: response fields
FieldDescription
resultobjectrequired

What the command returned, such as the IDs it created.

result.event_idstringrequired

The app record's event.

versionintegerrequired

The household version after the command.

Errors#

Every error has the same envelope: error.code, error.message, error.details, error.recovery and error.request_id.

Create or update the event an app's record owns: errors
StatusCodeWhen
400validation_failedA field is missing, misspelled or out of range. details.fields lists each problem.
401unauthenticatedThe request has no valid session.
404calendar_not_found
  • The calendar doesn't exist in this household.
  • The calendar must exist.
404person_not_found
  • The person doesn't exist in this household.
  • The people must exist.
404not_foundThe household doesn't exist, or you aren't a member of it.
409invalid_time_rangeEnding before starting is refused.
409invalid_recurrenceA rule Rigel can't read is refused.
409idempotency_key_reusedThe Idempotency-Key was already used for a different command.

Examples#

These are real. Each scenario is one of the command's test cases, run on a household when this site was built, and the response is what the API returned.

Creates the app's event on the default calendar

Request, curl
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
  -d '{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T11:00",
  "kind": "appointment",
  "location": "Basement"
}'
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: JSON.stringify({
    source_app: "maintenance",
    source_record_id: "job_01JC000000000000000000000A",
    title: "Furnace service",
    starts_at: "2025-11-20T09:00",
    ends_at: "2025-11-20T11:00",
    kind: "appointment",
    location: "Basement",
  }),
});
const data = await response.json();
Request, HTTP
POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA

{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T11:00",
  "kind": "appointment",
  "location": "Basement"
}
Response, 200
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01K9D9S2R0VAT4AFXF4BVFYB2R

{
  "result": {
    "event_id": "evt_01JC4N0000MBGE5RJ6Q7V6V6T8"
  },
  "version": 1
}

An event for one person goes on that person's own calendar

Request, curl
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
  -d '{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T11:00",
  "person_ids": [
    "per_01JC000000000000000000000B"
  ]
}'
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: JSON.stringify({
    source_app: "maintenance",
    source_record_id: "job_01JC000000000000000000000A",
    title: "Furnace service",
    starts_at: "2025-11-20T09:00",
    ends_at: "2025-11-20T11:00",
    person_ids: [
      "per_01JC000000000000000000000B",
    ],
  }),
});
const data = await response.json();
Request, HTTP
POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA

{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T11:00",
  "person_ids": [
    "per_01JC000000000000000000000B"
  ]
}
Response, 200
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01K9D9S2R04KK94Q2YQDE3GYD4

{
  "result": {
    "event_id": "evt_01JC4N0000MBGE5RJ6Q7V6V6T8"
  },
  "version": 1
}

A calendar_id is used when the event is made

Request, curl
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
  -d '{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T11:00",
  "calendar_id": "cal_01JC000000000000000000000C"
}'
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: JSON.stringify({
    source_app: "maintenance",
    source_record_id: "job_01JC000000000000000000000A",
    title: "Furnace service",
    starts_at: "2025-11-20T09:00",
    ends_at: "2025-11-20T11:00",
    calendar_id: "cal_01JC000000000000000000000C",
  }),
});
const data = await response.json();
Request, HTTP
POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA

{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T11:00",
  "calendar_id": "cal_01JC000000000000000000000C"
}
Response, 200
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01K9D9S2R07QKAM6Y0N3G9F2H1

{
  "result": {
    "event_id": "evt_01JC4N0000MBGE5RJ6Q7V6V6T8"
  },
  "version": 1
}

The Family calendar is made first when there are no calendars

Request, curl
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
  -d '{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T11:00"
}'
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: JSON.stringify({
    source_app: "maintenance",
    source_record_id: "job_01JC000000000000000000000A",
    title: "Furnace service",
    starts_at: "2025-11-20T09:00",
    ends_at: "2025-11-20T11:00",
  }),
});
const data = await response.json();
Request, HTTP
POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA

{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T11:00"
}
Response, 200
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01K9D9S2R0M2BK5CDKQ06K63D9

{
  "result": {
    "event_id": "evt_01JC4N0000VGW1STJ6TGXRB7FY"
  },
  "version": 1
}

Updating moves the event but leaves it on the calendar people put it on

Request, curl
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
  -d '{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-22T09:00",
  "ends_at": "2025-11-22T12:00",
  "calendar_id": "cal_01JC000000000000000000000A"
}'
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: JSON.stringify({
    source_app: "maintenance",
    source_record_id: "job_01JC000000000000000000000A",
    title: "Furnace service",
    starts_at: "2025-11-22T09:00",
    ends_at: "2025-11-22T12:00",
    calendar_id: "cal_01JC000000000000000000000A",
  }),
});
const data = await response.json();
Request, HTTP
POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA

{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-22T09:00",
  "ends_at": "2025-11-22T12:00",
  "calendar_id": "cal_01JC000000000000000000000A"
}
Response, 200
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01K9D9S2R0ZNN5DF0WX9B9M784

{
  "result": {
    "event_id": "evt_01JC000000000000000000000D"
  },
  "version": 1
}

People and reminders are left alone when not given

Request, curl
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
  -d '{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service (Smith HVAC)",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T11:00"
}'
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: JSON.stringify({
    source_app: "maintenance",
    source_record_id: "job_01JC000000000000000000000A",
    title: "Furnace service (Smith HVAC)",
    starts_at: "2025-11-20T09:00",
    ends_at: "2025-11-20T11:00",
  }),
});
const data = await response.json();
Request, HTTP
POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA

{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service (Smith HVAC)",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T11:00"
}
Response, 200
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01K9D9S2R0YFMAMMQC0PK691N1

{
  "result": {
    "event_id": "evt_01JC000000000000000000000D"
  },
  "version": 1
}

A moved repeating event takes its changes with it

Request, curl
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
  -d '{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T10:00",
  "ends_at": "2025-11-20T12:00",
  "recurrence": "FREQ=WEEKLY;BYDAY=TH"
}'
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: JSON.stringify({
    source_app: "maintenance",
    source_record_id: "job_01JC000000000000000000000A",
    title: "Furnace service",
    starts_at: "2025-11-20T10:00",
    ends_at: "2025-11-20T12:00",
    recurrence: "FREQ=WEEKLY;BYDAY=TH",
  }),
});
const data = await response.json();
Request, HTTP
POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA

{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T10:00",
  "ends_at": "2025-11-20T12:00",
  "recurrence": "FREQ=WEEKLY;BYDAY=TH"
}
Response, 200
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01K9D9S2R0V40YW98Q2GE2MJSM

{
  "result": {
    "event_id": "evt_01JC000000000000000000000D"
  },
  "version": 1
}

An all-day event

Request, curl
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
  -d '{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "start_date": "2025-11-20",
  "end_date": "2025-11-20"
}'
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: JSON.stringify({
    source_app: "maintenance",
    source_record_id: "job_01JC000000000000000000000A",
    title: "Furnace service",
    start_date: "2025-11-20",
    end_date: "2025-11-20",
  }),
});
const data = await response.json();
Request, HTTP
POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA

{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "start_date": "2025-11-20",
  "end_date": "2025-11-20"
}
Response, 200
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01K9D9S2R0MYKP7R61W27F7Z33

{
  "result": {
    "event_id": "evt_01JC4N0000MBGE5RJ6Q7V6V6T8"
  },
  "version": 1
}

The calendar must exist

Request, curl
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
  -d '{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T11:00",
  "calendar_id": "cal_01JC000000000000000000000Z"
}'
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: JSON.stringify({
    source_app: "maintenance",
    source_record_id: "job_01JC000000000000000000000A",
    title: "Furnace service",
    starts_at: "2025-11-20T09:00",
    ends_at: "2025-11-20T11:00",
    calendar_id: "cal_01JC000000000000000000000Z",
  }),
});
const data = await response.json();
Request, HTTP
POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA

{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T11:00",
  "calendar_id": "cal_01JC000000000000000000000Z"
}
Response, 404
HTTP/1.1 404 Not Found
Content-Type: application/json
X-Request-Id: req_01K9D9S2R0P03PB9JY1KEWS3WH

{
  "error": {
    "code": "calendar_not_found",
    "message": "That calendar isn't there any more. No changes were applied.",
    "details": {
      "calendar_id": "cal_01JC000000000000000000000Z"
    },
    "recovery": "Read the current state, then send a command that fits it.",
    "request_id": "req_01K9D9S2R0P03PB9JY1KEWS3WH"
  }
}

The people must exist

Request, curl
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
  -d '{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T11:00",
  "person_ids": [
    "per_01JC000000000000000000000Z"
  ]
}'
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: JSON.stringify({
    source_app: "maintenance",
    source_record_id: "job_01JC000000000000000000000A",
    title: "Furnace service",
    starts_at: "2025-11-20T09:00",
    ends_at: "2025-11-20T11:00",
    person_ids: [
      "per_01JC000000000000000000000Z",
    ],
  }),
});
const data = await response.json();
Request, HTTP
POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA

{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T11:00",
  "person_ids": [
    "per_01JC000000000000000000000Z"
  ]
}
Response, 404
HTTP/1.1 404 Not Found
Content-Type: application/json
X-Request-Id: req_01K9D9S2R0CEFPZS7J0F2HEMCD

{
  "error": {
    "code": "person_not_found",
    "message": "That person isn't in the household any more. No changes were applied.",
    "details": {
      "person_id": "per_01JC000000000000000000000Z"
    },
    "recovery": "Read the current state, then send a command that fits it.",
    "request_id": "req_01K9D9S2R0CEFPZS7J0F2HEMCD"
  }
}

Ending before starting is refused

Request, curl
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
  -d '{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T08:00"
}'
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: JSON.stringify({
    source_app: "maintenance",
    source_record_id: "job_01JC000000000000000000000A",
    title: "Furnace service",
    starts_at: "2025-11-20T09:00",
    ends_at: "2025-11-20T08:00",
  }),
});
const data = await response.json();
Request, HTTP
POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA

{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T08:00"
}
Response, 409
HTTP/1.1 409 Conflict
Content-Type: application/json
X-Request-Id: req_01K9D9S2R076FCEQAV7ZGYK1MT

{
  "error": {
    "code": "invalid_time_range",
    "message": "An event can't end before it starts. No changes were applied.",
    "details": {},
    "recovery": "Read the current state, then send a command that fits it.",
    "request_id": "req_01K9D9S2R076FCEQAV7ZGYK1MT"
  }
}

A rule Rigel can't read is refused

Request, curl
curl -X POST 'https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA' \
  -d '{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T11:00",
  "recurrence": "FREQ=HOURLY"
}'
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Idempotency-Key": "cmd_01JC4N0000AAAAAAAAAAAAAAAA",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: JSON.stringify({
    source_app: "maintenance",
    source_record_id: "job_01JC000000000000000000000A",
    title: "Furnace service",
    starts_at: "2025-11-20T09:00",
    ends_at: "2025-11-20T11:00",
    recurrence: "FREQ=HOURLY",
  }),
});
const data = await response.json();
Request, HTTP
POST /api/v1/households/hh_01K9BKKP003AHRZ6DMV29GQY5C/commands/calendar.source_event.put HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01JC4N0000AAAAAAAAAAAAAAAA

{
  "source_app": "maintenance",
  "source_record_id": "job_01JC000000000000000000000A",
  "title": "Furnace service",
  "starts_at": "2025-11-20T09:00",
  "ends_at": "2025-11-20T11:00",
  "recurrence": "FREQ=HOURLY"
}
Response, 409
HTTP/1.1 409 Conflict
Content-Type: application/json
X-Request-Id: req_01K9D9S2R06X967PMD2EC42ERM

{
  "error": {
    "code": "invalid_recurrence",
    "message": "That repeat rule doesn't work: Rigel can't repeat events by the hour. No changes were applied.",
    "details": {
      "problem": "Rigel can't repeat events by the hour."
    },
    "recovery": "Read the current state, then send a command that fits it.",
    "request_id": "req_01K9D9S2R06X967PMD2EC42ERM"
  }
}

Put a planned meal on the calendar

An app keeps one event for each of its records. Sending it again updates the same event.

Request, curl
curl -X POST 'https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/commands/calendar.source_event.put' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: cmd_01M6V9CSM9K0VJMXV0BGFGP7QH' \
  -d '{
  "source_app": "meals",
  "source_record_id": "mel_01M6V9CSFSFH4859KG4NM47HF2",
  "title": "Tomato and white bean orzo",
  "kind": "meal",
  "starts_at": "2026-11-09T18:00",
  "ends_at": "2026-11-09T18:45",
  "person_ids": [
    "per_01M6V9CS6RX26JK5KVYGRN22D2",
    "per_01M6V9CS744BQQH188FS6CXY9W",
    "per_01M6V9CS79TMYHDAM7FTA9ZK3Z",
    "per_01M6V9CS7CDAEP5VDA5T8R9TG6"
  ]
}'
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/commands/calendar.source_event.put", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Idempotency-Key": "cmd_01M6V9CSM9K0VJMXV0BGFGP7QH",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: JSON.stringify({
    source_app: "meals",
    source_record_id: "mel_01M6V9CSFSFH4859KG4NM47HF2",
    title: "Tomato and white bean orzo",
    kind: "meal",
    starts_at: "2026-11-09T18:00",
    ends_at: "2026-11-09T18:45",
    person_ids: [
      "per_01M6V9CS6RX26JK5KVYGRN22D2",
      "per_01M6V9CS744BQQH188FS6CXY9W",
      "per_01M6V9CS79TMYHDAM7FTA9ZK3Z",
      "per_01M6V9CS7CDAEP5VDA5T8R9TG6",
    ],
  }),
});
const data = await response.json();
Request, HTTP
POST /api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/commands/calendar.source_event.put HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json
Idempotency-Key: cmd_01M6V9CSM9K0VJMXV0BGFGP7QH

{
  "source_app": "meals",
  "source_record_id": "mel_01M6V9CSFSFH4859KG4NM47HF2",
  "title": "Tomato and white bean orzo",
  "kind": "meal",
  "starts_at": "2026-11-09T18:00",
  "ends_at": "2026-11-09T18:45",
  "person_ids": [
    "per_01M6V9CS6RX26JK5KVYGRN22D2",
    "per_01M6V9CS744BQQH188FS6CXY9W",
    "per_01M6V9CS79TMYHDAM7FTA9ZK3Z",
    "per_01M6V9CS7CDAEP5VDA5T8R9TG6"
  ]
}
Response, 200
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01M6V9CSM90Y07DAHZDS0YJ9T9

{
  "result": {
    "event_id": "evt_01M6V9CSM9VAVPZBE6BH6107WD"
  },
  "version": 103
}

For Rigel#

Rigel's tool for this command is calendar_source_event_put. Rigel runs this on its own, then says what it did. The agent guide has the rest.

Rigel is in early access, and sign-up is by invitation. Open Rigel