Skip to content
Rigel docs
Open Rigel

Rows changed since a version

sync.pull

GET/api/v1/households/{household_id}/pull

  • Route

Every synced row with a version greater than from, and every row deleted since. Send 0 for everything. A device also sends its client_id and after_seq (the highest sequence number it knows the household processed) and gets back what happened to its own pushed commands, the highest sequence number processed, and the household's schema version, which a device with fewer migrations must update to match. See the sync guide.

Parameters#

Rows changed since a version: parameters
FieldDescription
household_idpathstringrequired

The household's ID.

fromqueryinteger or nulloptional

The household version you have.

at least 0
client_idquerystringoptional

A device's ID. Give it to also get the outcomes of that device's pushed commands.

1 to 64 characters
after_seqqueryinteger or nulloptional

With client_id: report only this device's commands after this sequence number.

at least 0Default 0

Response#

200 The changes; with client_id, also the device's outcomes.

Rows changed since a version: response fields
FieldDescription
Shape 1, with last_client_seq, outcomes, schema_version
fromintegerrequired

The version the caller had.

versionintegerrequired

The household version these rows bring the caller up to.

rowsmap of arrays of objectsrequired

Changed rows by synced table name, in reference order.

tombstonesarray of objectsrequired

Rows deleted since from; remove them.

tombstones[].table_namestringrequiredNo description.
tombstones[].row_idstringrequiredNo description.
last_client_seqintegerrequired

The highest of this device's commands the server has processed, or 0.

outcomesarray of objectsrequired

This device's commands processed after after_seq, in order.

outcomes[].client_seqintegerrequired

The device's sequence number for the command.

outcomes[].command_idstringrequired

The command's ID, as the device sent it.

outcomes[].statusone of: applied, rejectedrequired

Whether the household applied the command or rejected it.

outcomes[].errorobject or nullrequired

Why a rejected command was rejected; null when it was applied.

outcomes[].error.codestringrequired

Stable snake_case code, such as person_not_found.

outcomes[].error.messagestringrequired

What went wrong, written for the person who issued the command.

schema_versionintegerrequired

How many household migrations the server has applied.

Shape 2
fromintegerrequired

The version the caller had.

versionintegerrequired

The household version these rows bring the caller up to.

rowsmap of arrays of objectsrequired

Changed rows by synced table name, in reference order.

tombstonesarray of objectsrequired

Rows deleted since from; remove them.

tombstones[].table_namestringrequiredNo description.
tombstones[].row_idstringrequiredNo description.

Errors#

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

Rows changed since a version: errors
StatusCodeWhen
400validation_failedA field is missing, misspelled or out of range. details.fields lists each problem.
401unauthenticatedThe request has no valid session.
403Read error.codeDescribed above.
404not_foundThe household doesn't exist, or you aren't a member of it.

Examples#

These are real. Each was recorded from a sample household, the Okafors, running through the whole API when this site was built.

Everything in the household

Every synced row with a version above from, and every row deleted since. Send 0 for everything.

Request, curl
curl 'https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/pull?from=0' \
  -H "Cookie: rigel_session=$RIGEL_SESSION"
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/pull?from=0", {
  headers: {
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
});
const data = await response.json();
Request, HTTP
GET /api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/pull?from=0 HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Response, 200
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01M6V9CS813K32SXJ9KAXJ3W7P

{
  "from": 0,
  "version": 13,
  "rows": {
    "file": [],
    "person": [
      {
        "id": "per_01M6V9CS6RX26JK5KVYGRN22D2",
        "created_at": 1794064671948,
        "updated_at": 1794064671948,
        "version": 1,
        "name": "Ada Okafor",
        "birth_date": null,
        "birth_date_precision": null,
        "user_id": "usr_01M6V9CS5XV66GR856KS52MTTZ",
        "sort_order": 0
      },
      {
        "id": "per_01M6V9CS744BQQH188FS6CXY9W",
        "created_at": 1794064671976,
        "updated_at": 1794064671976,
        "version": 2,
        "name": "Ben Okafor",
        "birth_date": null,
        "birth_date_precision": null,
        "user_id": null,
        "sort_order": 1
      },
      {
        "id": "per_01M6V9CS79TMYHDAM7FTA9ZK3Z",
        "created_at": 1794064671979,
        "updated_at": 1794064671979,
        "version": 3,
        "name": "Nia",
        "birth_date": "2018-03-14",
        "birth_date_precision": "day",
        "user_id": null,
        "sort_order": 2
      },
      {
        "id": "per_01M6V9CS7CDAEP5VDA5T8R9TG6",
        "created_at": 1794064671980,
        "updated_at": 1794064671980,
        "version": 4,
        "name": "Theo",
        "birth_date": "2021-08-01",
        "birth_date_precision": "month",
        "user_id": null,
        "sort_order": 3
      }
    ],
    "family_note": [
      {
        "id": "fnt_01M6V9CS7GXFHGYGZ4CFZG4J38",
        "created_at": 1794064671985,
        "updated_at": 1794064671985,
        "version": 6,
        "person_id": "per_01M6V9CS79TMYHDAM7FTA9ZK3Z",
        "text": "Nia wants to learn to bake. She likes measuring the flour.",
        "app": "recipes",
        "noted_at": 1794064671985
      },
      {
        "id": "fnt_01M6V9CS7HSE0X6FSYVAC690KF",
        "created_at": 1794064671986,
        "updated_at": 1794064671986,
        "version": 7,
        "person_id": "per_01M6V9CS744BQQH188FS6CXY9W",
        "text": "Ben doesn't eat shellfish.",
        "app": "meals",
        "noted_at": 1794064671986
      },
      {
        "id": "fnt_01M6V9CS7MX4PM9SC6Z6NVA2EA",
        "created_at": 1794064671989,
        "updated_at": 1794064671989,
        "version": 9,
        "person_id": null,
        "text": "Saturday mornings are for pancakes.",
        "app": null,
        "noted_at": 1794064671989
      },
      {
        "id": "fnt_01M6V9CS7E9NAJKGNWG7KBC8P4",
        "created_at": 1794064671983,
        "updated_at": 1794064671990,
        "version": 10,
        "person_id": "per_01M6V9CS7CDAEP5VDA5T8R9TG6",
        "text": "Theo isn't into spicy food lately. Mild chili is fine.",
        "app": "meals",
        "noted_at": 1794064671990
      },
      {
        "id": "fnt_01M6V9CS7KC15H3QT502N0J25K",
        "created_at": 1794064671988,
        "updated_at": 1794064671992,
        "version": 11,
        "person_id": null,
        "text": "Dinner is at 6:00 pm on weeknights.",
        "app": null,
        "noted_at": 1794064671988
      }
    ],
    "integration": [],
    "notification": [],
    "notification_mute": [],
    "folder": [],
    "document": [],
    "document_body": [],
    "document_extract": [],
    "document_version": [],
    "document_link": [],
    "document_import": [],
    "storage_location": [],
    "product_category": [],
    "product": [],
    "recipe": [],
    "recipe_ingredient": [],
    "recipe_step": [],
    "recipe_step_ingredient": [],
    "inventory_item": [],
    "dashboard_card": [],
    "app_picture": [],
    "agent_routine": [],
    "task": [],
    "task_dependency": [],
    "tag": [],
    "task_tag": [],
    "task_comment": [],
    "task_comment_mention": [],
    "task_comment_reaction": [],
    "task_watch": [],
    "task_link": [],
    "task_view": [],
    "task_view_value": [],
    "task_view_tag": [],
    "agent_trigger": [],
    "dish": [],
    "dish_ingredient": [],
    "meal": [],
    "meal_person": [],
    "meal_dish": [],
    "dish_combo_icon": [],
    "dish_combo_icon_dish": [],
    "meals_setting": [],
    "email_domain": [],
    "email_address": [],
    "email_domain_record": [],
    "email_correspondent": [],
    "email_thread": [],
    "email_connection": [],
    "email_connection_rule": [],
    "email_message": [],
    "email_message_recipient": [],
    "email_attachment": [],
    "email_action": [],
    "email_draft": [],
    "email_draft_recipient": [],
    "email_draft_attachment": [],
    "recipe_cook": [],
    "calendar": [
      {
        "id": "cal_01M6V9CS6R7BJ7D0KVCQQH1DCS",
        "created_at": 1794064671948,
        "updated_at": 1794064671948,
        "version": 1,
        "name": "Ada Okafor",
        "color": "calendar-2",
        "person_id": "per_01M6V9CS6RX26JK5KVYGRN22D2",
        "is_default": 0,
        "is_busy_only": 0,
        "is_visible": 1,
        "sort_order": 1
      },
      {
        "id": "cal_01M6V9CS6RESEHY2KVBGF3JX5Q",
        "created_at": 1794064671948,
        "updated_at": 1794064671948,
        "version": 1,
        "name": "Family",
        "color": "calendar-1",
        "person_id": null,
        "is_default": 1,
        "is_busy_only": 0,
        "is_visible": 1,
        "sort_order": 0
      }
    ],
    "calendar_event": [],
    "calendar_event_exception": [],
    "calendar_event_date": [],
    "calendar_event_attachment": [],
    "calendar_event_person": [],
    "calendar_event_reminder": [],
    "google_calendar": [],
    "google_calendar_link": [],
    "conversation": [],
    "custom_emoji": [],
    "sticker": [],
    "message": [],
    "message_attachment": [],
    "message_mention": [],
    "message_link": [],
    "message_reaction": [],
    "expression_pack": [],
    "expression_pack_item": [],
    "conversation_read": [],
    "conversation_follow": [],
    "sample_record": [],
    "property": [],
    "maintenance_location": [],
    "category": [],
    "model": [],
    "evidence": [],
    "asset": [],
    "asset_photo": [],
    "attribute": [],
    "identification": [],
    "identification_alternative": [],
    "part": [],
    "model_part": [],
    "asset_part": [],
    "warranty": [],
    "contractor": [],
    "contractor_contact": [],
    "maintenance_task": [],
    "maintenance_task_part": [],
    "maintenance_project": [],
    "maintenance_project_asset": [],
    "maintenance_project_update": [],
    "issue": [],
    "visit": [],
    "visit_asset": [],
    "visit_issue": [],
    "maintenance_task_completion": [],
    "invoice": [],
    "invoice_line": [],
    "ongoing_service": [],
    "store": [],
    "shopping_item": [],
    "shopping_item_meal": [],
    "shopping_item_recipe": [],
    "store_aisle": [],
    "store_product_aisle": [],
    "product_group": [],
    "product_group_member": [],
    "store_product_group": [],
    "store_product_override": [],
    "shopping_trip": [],
    "shopping_trip_item": [],
    "shopping_trip_email": []
  },
  "tombstones": [
    {
      "table_name": "family_note",
      "row_id": "fnt_01M6V9CS7WTZRFRHFAN0EGN39W"
    }
  ]
}

Pull as a device that is up to date

A device sends its client_id and the highest sequence number it has seen, and also learns what became of the commands it pushed.

Request, curl
curl 'https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/pull?from=13&client_id=cli_01M6PHONE7R3QWT8XK2VNB0Y5D&after_seq=0' \
  -H "Cookie: rigel_session=$RIGEL_SESSION"
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/pull?from=13&client_id=cli_01M6PHONE7R3QWT8XK2VNB0Y5D&after_seq=0", {
  headers: {
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
});
const data = await response.json();
Request, HTTP
GET /api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/pull?from=13&client_id=cli_01M6PHONE7R3QWT8XK2VNB0Y5D&after_seq=0 HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Response, 200
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01M6V9CS85YTY6GR9M0YHTT1KN

{
  "from": 13,
  "version": 13,
  "rows": {
    "file": [],
    "person": [],
    "family_note": [],
    "integration": [],
    "notification": [],
    "notification_mute": [],
    "folder": [],
    "document": [],
    "document_body": [],
    "document_extract": [],
    "document_version": [],
    "document_link": [],
    "document_import": [],
    "storage_location": [],
    "product_category": [],
    "product": [],
    "recipe": [],
    "recipe_ingredient": [],
    "recipe_step": [],
    "recipe_step_ingredient": [],
    "inventory_item": [],
    "dashboard_card": [],
    "app_picture": [],
    "agent_routine": [],
    "task": [],
    "task_dependency": [],
    "tag": [],
    "task_tag": [],
    "task_comment": [],
    "task_comment_mention": [],
    "task_comment_reaction": [],
    "task_watch": [],
    "task_link": [],
    "task_view": [],
    "task_view_value": [],
    "task_view_tag": [],
    "agent_trigger": [],
    "dish": [],
    "dish_ingredient": [],
    "meal": [],
    "meal_person": [],
    "meal_dish": [],
    "dish_combo_icon": [],
    "dish_combo_icon_dish": [],
    "meals_setting": [],
    "email_domain": [],
    "email_address": [],
    "email_domain_record": [],
    "email_correspondent": [],
    "email_thread": [],
    "email_connection": [],
    "email_connection_rule": [],
    "email_message": [],
    "email_message_recipient": [],
    "email_attachment": [],
    "email_action": [],
    "email_draft": [],
    "email_draft_recipient": [],
    "email_draft_attachment": [],
    "recipe_cook": [],
    "calendar": [],
    "calendar_event": [],
    "calendar_event_exception": [],
    "calendar_event_date": [],
    "calendar_event_attachment": [],
    "calendar_event_person": [],
    "calendar_event_reminder": [],
    "google_calendar": [],
    "google_calendar_link": [],
    "conversation": [],
    "custom_emoji": [],
    "sticker": [],
    "message": [],
    "message_attachment": [],
    "message_mention": [],
    "message_link": [],
    "message_reaction": [],
    "expression_pack": [],
    "expression_pack_item": [],
    "conversation_read": [],
    "conversation_follow": [],
    "sample_record": [],
    "property": [],
    "maintenance_location": [],
    "category": [],
    "model": [],
    "evidence": [],
    "asset": [],
    "asset_photo": [],
    "attribute": [],
    "identification": [],
    "identification_alternative": [],
    "part": [],
    "model_part": [],
    "asset_part": [],
    "warranty": [],
    "contractor": [],
    "contractor_contact": [],
    "maintenance_task": [],
    "maintenance_task_part": [],
    "maintenance_project": [],
    "maintenance_project_asset": [],
    "maintenance_project_update": [],
    "issue": [],
    "visit": [],
    "visit_asset": [],
    "visit_issue": [],
    "maintenance_task_completion": [],
    "invoice": [],
    "invoice_line": [],
    "ongoing_service": [],
    "store": [],
    "shopping_item": [],
    "shopping_item_meal": [],
    "shopping_item_recipe": [],
    "store_aisle": [],
    "store_product_aisle": [],
    "product_group": [],
    "product_group_member": [],
    "store_product_group": [],
    "store_product_override": [],
    "shopping_trip": [],
    "shopping_trip_item": [],
    "shopping_trip_email": []
  },
  "tombstones": [],
  "last_client_seq": 0,
  "outcomes": [],
  "schema_version": 34
}

Pull what happened to a device's commands

outcomes lists each command after after_seq as applied or rejected, with the reason.

Request, curl
curl 'https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/pull?from=13&client_id=cli_01M6PHONE7R3QWT8XK2VNB0Y5D&after_seq=0' \
  -H "Cookie: rigel_session=$RIGEL_SESSION"
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/pull?from=13&client_id=cli_01M6PHONE7R3QWT8XK2VNB0Y5D&after_seq=0", {
  headers: {
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
});
const data = await response.json();
Request, HTTP
GET /api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/pull?from=13&client_id=cli_01M6PHONE7R3QWT8XK2VNB0Y5D&after_seq=0 HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Response, 200
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01M6V9CS8DF6P84N5ANDG5X6PF

{
  "from": 13,
  "version": 15,
  "rows": {
    "file": [],
    "person": [],
    "family_note": [
      {
        "id": "fnt_01M6V9CS85J9R3PRDTEYTGSZXV",
        "created_at": 1794064492005,
        "updated_at": 1794064492005,
        "version": 14,
        "person_id": "per_01M6V9CS79TMYHDAM7FTA9ZK3Z",
        "text": "Nia is practicing her recorder for the winter concert.",
        "app": null,
        "noted_at": 1794064492005
      },
      {
        "id": "fnt_01M6V9CS85VEP4QJ62EEW4F7EB",
        "created_at": 1794064612005,
        "updated_at": 1794064612005,
        "version": 15,
        "person_id": null,
        "text": "The concert is the evening of Dec 10.",
        "app": "calendar",
        "noted_at": 1794064612005
      }
    ],
    "integration": [],
    "notification": [],
    "notification_mute": [],
    "folder": [],
    "document": [],
    "document_body": [],
    "document_extract": [],
    "document_version": [],
    "document_link": [],
    "document_import": [],
    "storage_location": [],
    "product_category": [],
    "product": [],
    "recipe": [],
    "recipe_ingredient": [],
    "recipe_step": [],
    "recipe_step_ingredient": [],
    "inventory_item": [],
    "dashboard_card": [],
    "app_picture": [],
    "agent_routine": [],
    "task": [],
    "task_dependency": [],
    "tag": [],
    "task_tag": [],
    "task_comment": [],
    "task_comment_mention": [],
    "task_comment_reaction": [],
    "task_watch": [],
    "task_link": [],
    "task_view": [],
    "task_view_value": [],
    "task_view_tag": [],
    "agent_trigger": [],
    "dish": [],
    "dish_ingredient": [],
    "meal": [],
    "meal_person": [],
    "meal_dish": [],
    "dish_combo_icon": [],
    "dish_combo_icon_dish": [],
    "meals_setting": [],
    "email_domain": [],
    "email_address": [],
    "email_domain_record": [],
    "email_correspondent": [],
    "email_thread": [],
    "email_connection": [],
    "email_connection_rule": [],
    "email_message": [],
    "email_message_recipient": [],
    "email_attachment": [],
    "email_action": [],
    "email_draft": [],
    "email_draft_recipient": [],
    "email_draft_attachment": [],
    "recipe_cook": [],
    "calendar": [],
    "calendar_event": [],
    "calendar_event_exception": [],
    "calendar_event_date": [],
    "calendar_event_attachment": [],
    "calendar_event_person": [],
    "calendar_event_reminder": [],
    "google_calendar": [],
    "google_calendar_link": [],
    "conversation": [],
    "custom_emoji": [],
    "sticker": [],
    "message": [],
    "message_attachment": [],
    "message_mention": [],
    "message_link": [],
    "message_reaction": [],
    "expression_pack": [],
    "expression_pack_item": [],
    "conversation_read": [],
    "conversation_follow": [],
    "sample_record": [],
    "property": [],
    "maintenance_location": [],
    "category": [],
    "model": [],
    "evidence": [],
    "asset": [],
    "asset_photo": [],
    "attribute": [],
    "identification": [],
    "identification_alternative": [],
    "part": [],
    "model_part": [],
    "asset_part": [],
    "warranty": [],
    "contractor": [],
    "contractor_contact": [],
    "maintenance_task": [],
    "maintenance_task_part": [],
    "maintenance_project": [],
    "maintenance_project_asset": [],
    "maintenance_project_update": [],
    "issue": [],
    "visit": [],
    "visit_asset": [],
    "visit_issue": [],
    "maintenance_task_completion": [],
    "invoice": [],
    "invoice_line": [],
    "ongoing_service": [],
    "store": [],
    "shopping_item": [],
    "shopping_item_meal": [],
    "shopping_item_recipe": [],
    "store_aisle": [],
    "store_product_aisle": [],
    "product_group": [],
    "product_group_member": [],
    "store_product_group": [],
    "store_product_override": [],
    "shopping_trip": [],
    "shopping_trip_item": [],
    "shopping_trip_email": []
  },
  "tombstones": [],
  "last_client_seq": 3,
  "outcomes": [
    {
      "client_seq": 1,
      "command_id": "cmd_01M6V9CS85QPQN4JDKVH308QYZ",
      "status": "applied",
      "error": null
    },
    {
      "client_seq": 2,
      "command_id": "cmd_01M6V9CS85HPG7JWHT24KJWDZQ",
      "status": "rejected",
      "error": {
        "code": "note_not_found",
        "message": "That note isn't there any more."
      }
    },
    {
      "client_seq": 3,
      "command_id": "cmd_01M6V9CS85HMC5XPRT3NDRR6QV",
      "status": "applied",
      "error": null
    }
  ],
  "schema_version": 34
}

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