Skip to content
Rigel docs
Open Rigel

Upload a file's missing copy

files.add_copy

PUT/api/v1/households/{household_id}/files/{file_id}/{copy}

  • Route

Adds the original or the display copy a file doesn't have yet, sent as the raw request body. A display copy also needs width and height. A file that already has that copy answers 409 file_copy_exists, which a client retrying a dropped connection treats as success. See the files guide.

Parameters#

Upload a file's missing copy: parameters
FieldDescription
household_idpathstringrequired

The household's ID.

file_idpathstringrequired

The file's ID, such as fil_01JC…

copypathone of: original, displayrequired

Which copy: original or display.

widthqueryintegeroptional

The display copy's width in pixels, 1–4096. Required for a display copy.

1 to 4,096
heightqueryintegeroptional

The display copy's height in pixels, 1–4096. Required for a display copy.

1 to 4,096
Content-Typeheaderstringrequired

The media type of the bytes, such as image/jpeg. Parameters are ignored.

Content-Lengthheaderstringrequired

The exact size of the body in bytes.

Request body#

The body is the raw bytes, sent as */*. The file's bytes, exactly as they are.

Response#

200 The copy was stored.

Upload a file's missing copy: response fields
FieldDescription
idstringrequired

A file ID, such as fil_01JC0000000000000000000000.

namestringrequired

The file's name as uploaded, used for downloads.

kindone of: image, pdf, video, audio, otherrequired

What the file is: image, pdf, video, audio, or other (anything else, which is only ever offered as a download).

originalobject or nullrequired

The bytes as uploaded, or null until the original is stored.

original.typestringrequired

The original's media type, such as image/heic.

original.sizeintegerrequired

The original's size in bytes.

displayobject or nullrequired

The image that stands for the file on screen, or null when it has none.

display.typestringrequired

The display copy's media type: image/jpeg, image/webp or image/png.

display.sizeintegerrequired

The display copy's size in bytes.

display.widthintegerrequired

The display copy's width in pixels.

display.heightintegerrequired

The display copy's height in pixels.

created_atstring (date-time)required

When the file was first stored.

Errors#

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

Upload a file's missing copy: errors
StatusCodeWhen
400validation_failedA field is missing, misspelled or out of range. details.fields lists each problem.
401unauthenticatedThe request has no valid session.
404not_foundThe household doesn't exist, or you aren't a member of it.
409Read error.codeDescribed above.
411Read error.codeDescribed above.
413Read error.codeDescribed above.
415Read error.codeDescribed above.
429Read error.codeDescribed above.

Examples#

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

Add the display copy

A phone makes a smaller copy for screens and sends it second. A display copy needs its width and height.

Request, curl
curl -X PUT 'https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/files/fil_01M6V9CS96RRJQEBVXVCKMMR0T/display?width=96&height=64' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: image/png' \
  --data-binary @photo.jpg
Request, TypeScript
import { readFile } from "node:fs/promises";

const response = await fetch("https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/files/fil_01M6V9CS96RRJQEBVXVCKMMR0T/display?width=96&height=64", {
  method: "PUT",
  headers: {
    "Content-Type": "image/png",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: await readFile("photo.jpg"),
});
const data = await response.json();
Request, HTTP
PUT /api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/files/fil_01M6V9CS96RRJQEBVXVCKMMR0T/display?width=96&height=64 HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: image/png
Content-Length: 342

(342 bytes of image/png; The picture's bytes, a PNG.)
Response, 200
HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: req_01M6V9CS9JGB776GF77JRAC0GC

{
  "id": "fil_01M6V9CS96RRJQEBVXVCKMMR0T",
  "name": "pantry-middle-shelf.png",
  "kind": "image",
  "original": {
    "type": "image/png",
    "size": 655
  },
  "display": {
    "type": "image/png",
    "size": 342,
    "width": 96,
    "height": 64
  },
  "created_at": "2026-11-07T15:17:52.045Z"
}

Add a copy the file already has

A client that retries after a dropped connection can treat this as success.

Request, curl
curl -X PUT 'https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/files/fil_01M6V9CS96RRJQEBVXVCKMMR0T/original' \
  -H "Cookie: rigel_session=$RIGEL_SESSION" \
  -H 'Content-Type: image/png' \
  --data-binary @photo.jpg
Request, TypeScript
import { readFile } from "node:fs/promises";

const response = await fetch("https://rigel.house/api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/files/fil_01M6V9CS96RRJQEBVXVCKMMR0T/original", {
  method: "PUT",
  headers: {
    "Content-Type": "image/png",
    Cookie: `rigel_session=${process.env.RIGEL_SESSION}`,
  },
  body: await readFile("photo.jpg"),
});
const data = await response.json();
Request, HTTP
PUT /api/v1/households/hh_01M6V9CS6GGVFCY7NAS8ZTQV95/files/fil_01M6V9CS96RRJQEBVXVCKMMR0T/original HTTP/1.1
Host: rigel.house
Cookie: rigel_session=<your session>
Content-Type: image/png
Content-Length: 655

(655 bytes of image/png; The picture's bytes, a PNG.)
Response, 409
HTTP/1.1 409 Conflict
Content-Type: application/json
X-Request-Id: req_01M6V9CS9PMP8ZEGZM9401XTCQ

{
  "error": {
    "code": "file_copy_exists",
    "message": "That file already has its original copy. No changes were applied.",
    "details": {
      "file_id": "fil_01M6V9CS96RRJQEBVXVCKMMR0T",
      "copy": "original"
    },
    "recovery": "Read the file's current state, then try again.",
    "request_id": "req_01M6V9CS9PMP8ZEGZM9401XTCQ"
  }
}

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