Skip to content
Rigel docs
Open Rigel

Send a device's queued commands

sync.push

POST/api/v1/households/{household_id}/sync/push

  • Route

Runs the commands a device queued while it was offline, in client_seq order, each as you. A sequence number the household already processed is skipped, so a resend is safe. A gap makes it stop and answer with resend_from. A command it can't run (it doesn't parse, it isn't a command, or it fails) is recorded as rejected and does not block the ones after it; the next pull says which were rejected and why. A client_id belongs to the first user who pushed with it. See the sync guide.

Parameters#

Send a device's queued commands: parameters
FieldDescription
household_idpathstringrequired

The household's ID.

Request body#

JSON, as application/json.

Send a device's queued commands: request body fields
FieldDescription
client_idstringrequired

An installation's ID (cli_…), made once and kept in its local database. It belongs to one user.

1 to 64 characters
commandsarray of objectsrequired

Queued commands in client_seq order.

at most 500 items
commands[].client_seqintegerrequired

This device's sequence number for the command, from 1.

at least 1
commands[].command_idstringrequired

The command's ID (cmd_…); the same on every retry.

commands[].namestringrequired

The command's name, such as family.note.record.

at most 120 characters
commands[].inputanyoptional

The command's input, as the device ran it.

commands[].issued_atintegerrequired

When the person issued it on the device, UTC milliseconds.

Response#

200 How far the household got through the commands.

Send a device's queued commands: response fields
FieldDescription
last_client_seqintegerrequired

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

resend_frominteger or nullrequired

When there was a gap, the client_seq to resend from; otherwise null.

Errors#

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

Send a device's queued commands: 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.

Send a device's queued commands

Runs them in client_seq order, as you. One the household can't run is recorded as rejected and doesn't hold up the rest.

Request, curl
curl -X POST 'https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/sync/push' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: application/json' \
  -d '{
  "client_id": "cli_01M6PHONE7R3QWT8XK2VNB0Y5D",
  "commands": [
    {
      "client_seq": 1,
      "command_id": "cmd_01M6V9CS85QPQN4JDKVH308QYZ",
      "name": "family.note.record",
      "input": {
        "person_id": "per_01M6V9CS79TMYHDAM7FTA9ZK3Z",
        "text": "Nia is practicing her recorder for the winter concert."
      },
      "issued_at": 1794064492005
    },
    {
      "client_seq": 2,
      "command_id": "cmd_01M6V9CS85HPG7JWHT24KJWDZQ",
      "name": "family.note.forget",
      "input": {
        "note_id": "fnt_01JC0000000000000000000000"
      },
      "issued_at": 1794064552005
    },
    {
      "client_seq": 3,
      "command_id": "cmd_01M6V9CS85HMC5XPRT3NDRR6QV",
      "name": "family.note.record",
      "input": {
        "text": "The concert is the evening of Dec 10.",
        "app": "calendar"
      },
      "issued_at": 1794064612005
    }
  ]
}'
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/sync/push", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: JSON.stringify({
    client_id: "cli_01M6PHONE7R3QWT8XK2VNB0Y5D",
    commands: [
      {
        client_seq: 1,
        command_id: "cmd_01M6V9CS85QPQN4JDKVH308QYZ",
        name: "family.note.record",
        input: {
          person_id: "per_01M6V9CS79TMYHDAM7FTA9ZK3Z",
          text: "Nia is practicing her recorder for the winter concert.",
        },
        issued_at: 1794064492005,
      },
      {
        client_seq: 2,
        command_id: "cmd_01M6V9CS85HPG7JWHT24KJWDZQ",
        name: "family.note.forget",
        input: {
          note_id: "fnt_01JC0000000000000000000000",
        },
        issued_at: 1794064552005,
      },
      {
        client_seq: 3,
        command_id: "cmd_01M6V9CS85HMC5XPRT3NDRR6QV",
        name: "family.note.record",
        input: {
          text: "The concert is the evening of Dec 10.",
          app: "calendar",
        },
        issued_at: 1794064612005,
      },
    ],
  }),
});
const data = await response.json();
Request, HTTP
POST /api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/sync/push HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json

{
  "client_id": "cli_01M6PHONE7R3QWT8XK2VNB0Y5D",
  "commands": [
    {
      "client_seq": 1,
      "command_id": "cmd_01M6V9CS85QPQN4JDKVH308QYZ",
      "name": "family.note.record",
      "input": {
        "person_id": "per_01M6V9CS79TMYHDAM7FTA9ZK3Z",
        "text": "Nia is practicing her recorder for the winter concert."
      },
      "issued_at": 1794064492005
    },
    {
      "client_seq": 2,
      "command_id": "cmd_01M6V9CS85HPG7JWHT24KJWDZQ",
      "name": "family.note.forget",
      "input": {
        "note_id": "fnt_01JC0000000000000000000000"
      },
      "issued_at": 1794064552005
    },
    {
      "client_seq": 3,
      "command_id": "cmd_01M6V9CS85HMC5XPRT3NDRR6QV",
      "name": "family.note.record",
      "input": {
        "text": "The concert is the evening of Dec 10.",
        "app": "calendar"
      },
      "issued_at": 1794064612005
    }
  ]
}
Response, 200
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01M6V9CS89WF75ZWWHMZE1YNSJ

{
  "last_client_seq": 3,
  "resend_from": null
}

Send the same commands again

A resend after a lost response changes nothing: sequence numbers the household already processed are skipped.

Request, curl
curl -X POST 'https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/sync/push' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: application/json' \
  -d '{
  "client_id": "cli_01M6PHONE7R3QWT8XK2VNB0Y5D",
  "commands": [
    {
      "client_seq": 1,
      "command_id": "cmd_01M6V9CS85QPQN4JDKVH308QYZ",
      "name": "family.note.record",
      "input": {
        "person_id": "per_01M6V9CS79TMYHDAM7FTA9ZK3Z",
        "text": "Nia is practicing her recorder for the winter concert."
      },
      "issued_at": 1794064492005
    },
    {
      "client_seq": 2,
      "command_id": "cmd_01M6V9CS85HPG7JWHT24KJWDZQ",
      "name": "family.note.forget",
      "input": {
        "note_id": "fnt_01JC0000000000000000000000"
      },
      "issued_at": 1794064552005
    },
    {
      "client_seq": 3,
      "command_id": "cmd_01M6V9CS85HMC5XPRT3NDRR6QV",
      "name": "family.note.record",
      "input": {
        "text": "The concert is the evening of Dec 10.",
        "app": "calendar"
      },
      "issued_at": 1794064612005
    }
  ]
}'
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/sync/push", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: JSON.stringify({
    client_id: "cli_01M6PHONE7R3QWT8XK2VNB0Y5D",
    commands: [
      {
        client_seq: 1,
        command_id: "cmd_01M6V9CS85QPQN4JDKVH308QYZ",
        name: "family.note.record",
        input: {
          person_id: "per_01M6V9CS79TMYHDAM7FTA9ZK3Z",
          text: "Nia is practicing her recorder for the winter concert.",
        },
        issued_at: 1794064492005,
      },
      {
        client_seq: 2,
        command_id: "cmd_01M6V9CS85HPG7JWHT24KJWDZQ",
        name: "family.note.forget",
        input: {
          note_id: "fnt_01JC0000000000000000000000",
        },
        issued_at: 1794064552005,
      },
      {
        client_seq: 3,
        command_id: "cmd_01M6V9CS85HMC5XPRT3NDRR6QV",
        name: "family.note.record",
        input: {
          text: "The concert is the evening of Dec 10.",
          app: "calendar",
        },
        issued_at: 1794064612005,
      },
    ],
  }),
});
const data = await response.json();
Request, HTTP
POST /api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/sync/push HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json

{
  "client_id": "cli_01M6PHONE7R3QWT8XK2VNB0Y5D",
  "commands": [
    {
      "client_seq": 1,
      "command_id": "cmd_01M6V9CS85QPQN4JDKVH308QYZ",
      "name": "family.note.record",
      "input": {
        "person_id": "per_01M6V9CS79TMYHDAM7FTA9ZK3Z",
        "text": "Nia is practicing her recorder for the winter concert."
      },
      "issued_at": 1794064492005
    },
    {
      "client_seq": 2,
      "command_id": "cmd_01M6V9CS85HPG7JWHT24KJWDZQ",
      "name": "family.note.forget",
      "input": {
        "note_id": "fnt_01JC0000000000000000000000"
      },
      "issued_at": 1794064552005
    },
    {
      "client_seq": 3,
      "command_id": "cmd_01M6V9CS85HMC5XPRT3NDRR6QV",
      "name": "family.note.record",
      "input": {
        "text": "The concert is the evening of Dec 10.",
        "app": "calendar"
      },
      "issued_at": 1794064612005
    }
  ]
}
Response, 200
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01M6V9CS8B5FRSM60JFSE9S885

{
  "last_client_seq": 3,
  "resend_from": null
}

Skip ahead in the queue

A gap makes the household stop and say where to resend from.

Request, curl
curl -X POST 'https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/sync/push' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: application/json' \
  -d '{
  "client_id": "cli_01M6PHONE7R3QWT8XK2VNB0Y5D",
  "commands": [
    {
      "client_seq": 6,
      "command_id": "cmd_01M6V9CS8CDAX3GJBVPNZF0XRK",
      "name": "family.note.record",
      "input": {
        "text": "Out of order."
      },
      "issued_at": 1794064792012
    }
  ]
}'
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/sync/push", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: JSON.stringify({
    client_id: "cli_01M6PHONE7R3QWT8XK2VNB0Y5D",
    commands: [
      {
        client_seq: 6,
        command_id: "cmd_01M6V9CS8CDAX3GJBVPNZF0XRK",
        name: "family.note.record",
        input: {
          text: "Out of order.",
        },
        issued_at: 1794064792012,
      },
    ],
  }),
});
const data = await response.json();
Request, HTTP
POST /api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/sync/push HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json

{
  "client_id": "cli_01M6PHONE7R3QWT8XK2VNB0Y5D",
  "commands": [
    {
      "client_seq": 6,
      "command_id": "cmd_01M6V9CS8CDAX3GJBVPNZF0XRK",
      "name": "family.note.record",
      "input": {
        "text": "Out of order."
      },
      "issued_at": 1794064792012
    }
  ]
}
Response, 200
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01M6V9CS8CGKFBKNDMG6K2QRND

{
  "last_client_seq": 3,
  "resend_from": 4
}

A push that doesn't fit the protocol

Request, curl
curl -X POST 'https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/sync/push' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: application/json' \
  -d '{
  "client_id": "",
  "commands": [
    {
      "client_seq": 1,
      "command_id": "not-a-command-id",
      "name": "family.note.record",
      "issued_at": 1
    }
  ]
}'
Request, TypeScript
const response = await fetch("https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/sync/push", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: JSON.stringify({
    client_id: "",
    commands: [
      {
        client_seq: 1,
        command_id: "not-a-command-id",
        name: "family.note.record",
        issued_at: 1,
      },
    ],
  }),
});
const data = await response.json();
Request, HTTP
POST /api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/sync/push HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: application/json

{
  "client_id": "",
  "commands": [
    {
      "client_seq": 1,
      "command_id": "not-a-command-id",
      "name": "family.note.record",
      "issued_at": 1
    }
  ]
}
Response, 400
HTTP/1.1 400 Bad Request
Content-Type: application/json
X-Request-Id: req_01M6V9CS8GZ1PKDMPHBZC2ARF2

{
  "error": {
    "code": "validation_failed",
    "message": "The request has invalid fields. No changes were applied.",
    "details": {
      "fields": [
        {
          "field": "client_id",
          "problem": "Too small: expected string to have >=1 characters"
        },
        {
          "field": "commands[0].command_id",
          "problem": "must be a command ID starting with cmd_"
        },
        {
          "field": "commands[0].input",
          "problem": "Invalid input: expected nonoptional, received undefined"
        }
      ]
    },
    "recovery": "Correct each field listed in details.fields, then send the request again.",
    "request_id": "req_01M6V9CS8GZ1PKDMPHBZC2ARF2"
  }
}

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