Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/deuxfleurs-org/garage/llms.txt

Use this file to discover all available pages before exploring further.

Single Item Operations

ReadItem

Read a single item by partition key and sort key. Endpoint: GET /<bucket>/<partition_key>?sort_key=<sort_key> Query Parameters:
ParameterRequiredDescription
sort_keyYesThe sort key of the item to read
Response Formats: Values can be returned in two formats, controlled by the Accept header:
  1. JSON format (Content-Type: application/json)
    • Returns a JSON array of base64-encoded values
    • Tombstones are represented as null
    • Always used when multiple concurrent values exist
  2. Binary format (Content-Type: application/octet-stream)
    • Returns the single value directly as binary
    • Returns HTTP 204 NO CONTENT for tombstones
    • Returns HTTP 409 CONFLICT if multiple concurrent values exist
Accept Header Behavior:
  • No Accept header or Accept: application/json → JSON format
  • Accept: application/octet-stream → Binary format if single value, 409 if conflicts
  • Accept: application/json, application/octet-stream → Binary for single value, JSON for conflicts
  • Other values → HTTP 406 NOT ACCEPTABLE
Response Headers:
  • X-Garage-Causality-Token: Causality token for this item (required for writes)
Example Request:
GET /my-bucket/mailboxes?sort_key=INBOX HTTP/1.1
Host: k2v.garage.example.com
Example Response (JSON):
HTTP/1.1 200 OK
X-Garage-Causality-Token: opaquetoken123
Content-Type: application/json

[
  "YjY0Y3J5cHRvYmxvYjEyMw==",
  "YjY0Y3J5cHRvYmxvYicxMjM="
]
Example Response (Tombstone):
HTTP/1.1 200 OK
X-Garage-Causality-Token: opaquetoken999
Content-Type: application/json

[null]
Example Response (Binary):
HTTP/1.1 200 OK
X-Garage-Causality-Token: opaquetoken123
Content-Type: application/octet-stream

<binary data>

InsertItem

Insert or update a single item. Endpoint: PUT /<bucket>/<partition_key>?sort_key=<sort_key> Query Parameters:
ParameterRequiredDescription
sort_keyYesThe sort key of the item to insert
Request Headers:
HeaderRequiredDescription
X-Garage-Causality-TokenNoCausality token from previous read. Omit for first write to key.
Request Body: Binary data (the value to store) Response: HTTP 204 NO CONTENT on success Example Request:
PUT /my-bucket/mailboxes?sort_key=INBOX HTTP/1.1
Host: k2v.garage.example.com
X-Garage-Causality-Token: opaquetoken123
Content-Length: 1024

<binary data>
Example Response:
HTTP/1.1 204 No Content
If you omit the X-Garage-Causality-Token header, the write will create a concurrent value rather than overwriting existing values. Always include the causality token when updating existing items.

DeleteItem

Delete a single item by creating a tombstone. Endpoint: DELETE /<bucket>/<partition_key>?sort_key=<sort_key> Query Parameters:
ParameterRequiredDescription
sort_keyYesThe sort key of the item to delete
Request Headers:
HeaderRequiredDescription
X-Garage-Causality-TokenYesCausality token from previous read
Response: HTTP 204 NO CONTENT on success Example Request:
DELETE /my-bucket/mailboxes?sort_key=INBOX HTTP/1.1
Host: k2v.garage.example.com
X-Garage-Causality-Token: opaquetoken123
Example Response:
HTTP/1.1 204 NO CONTENT
The X-Garage-Causality-Token header is mandatory for delete operations. This ensures the delete is causally related to values you’ve read.

PollItem

Wait for changes to a single item. Endpoint: GET /<bucket>/<partition_key>?sort_key=<sort_key>&causality_token=<token> Query Parameters:
ParameterRequiredDefaultDescription
sort_keyYes-The sort key of the item to poll
causality_tokenYes-The causality token from your last read
timeoutNo300Timeout in seconds (max 600)
Response: Same format as ReadItem, or HTTP 304 NOT MODIFIED if timeout expires Example Request:
GET /my-bucket/mailboxes?sort_key=INBOX&causality_token=opaquetoken123&timeout=60 HTTP/1.1
Host: k2v.garage.example.com
Example Response (Updated):
HTTP/1.1 200 OK
X-Garage-Causality-Token: opaquetoken456
Content-Type: application/json

["bmV3dmFsdWU="]
Example Response (No Change):
HTTP/1.1 304 NOT MODIFIED

Batch Operations

ReadBatch

Read multiple items in a single request. Endpoint: POST /<bucket>?search or SEARCH /<bucket> Request Body: JSON array of query objects Query Object Fields:
FieldRequiredDefaultDescription
partitionKeyYes-Partition key to search in
prefixNonullFilter sort keys by prefix
startNonullFirst sort key to read
endNonullLast sort key to read (exclusive)
limitNonullMaximum number of items to return
reverseNofalseIterate in reverse order
singleItemNofalseReturn only item with sort key = start
conflictsOnlyNofalseReturn only items with conflicts
tombstonesNofalseInclude tombstone entries
Response: JSON array of result objects (one per query) Result Object Fields:
FieldDescription
partitionKeyEcho of query partition key
prefix, start, end, limit, reverseEcho of query parameters
singleItem, conflictsOnly, tombstonesEcho of query flags
itemsArray of item objects
moreBoolean indicating more items available
nextStartSort key to use for next page (if more is true)
Item Object Format:
{
  "sk": "<sort_key>",
  "ct": "<causality_token>",
  "v": ["<base64_value1>", "<base64_value2>", ...]
}
Example Request:
POST /my-bucket?search HTTP/1.1
Host: k2v.garage.example.com
Content-Type: application/json

[
  {
    "partitionKey": "mailboxes"
  },
  {
    "partitionKey": "mailbox:INBOX",
    "start": "001892831",
    "limit": 3
  },
  {
    "partitionKey": "keys",
    "start": "0",
    "singleItem": true
  }
]
Example Response:
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "partitionKey": "mailboxes",
    "prefix": null,
    "start": null,
    "end": null,
    "limit": null,
    "reverse": false,
    "conflictsOnly": false,
    "tombstones": false,
    "singleItem": false,
    "items": [
      {
        "sk": "INBOX",
        "ct": "opaquetoken123",
        "v": ["YjY0Y3J5cHRvYmxvYjEyMw==", "YjY0Y3J5cHRvYmxvYicxMjM="]
      },
      {
        "sk": "Trash",
        "ct": "opaquetoken456",
        "v": ["YjY0Y3J5cHRvYmxvYjQ1Ng=="]
      }
    ],
    "more": false,
    "nextStart": null
  },
  {
    "partitionKey": "mailbox:INBOX",
    "prefix": null,
    "start": "001892831",
    "end": null,
    "limit": 3,
    "reverse": false,
    "conflictsOnly": false,
    "tombstones": false,
    "singleItem": false,
    "items": [
      {
        "sk": "001892831",
        "ct": "opaquetoken321",
        "v": ["YjY0Y3J5cHRvYmxvYjMyMQ=="]
      }
    ],
    "more": true,
    "nextStart": "001892898"
  },
  {
    "partitionKey": "keys",
    "prefix": null,
    "start": "0",
    "end": null,
    "limit": null,
    "reverse": false,
    "conflictsOnly": false,
    "tombstones": false,
    "singleItem": true,
    "items": [
      {
        "sk": "0",
        "ct": "opaquetoken999",
        "v": ["YjY0YmluYXJ5c3R1ZmY5OTk="]
      }
    ],
    "more": false,
    "nextStart": null
  }
]
When singleItem is true, you cannot specify prefix, end, limit, or reverse parameters.

InsertBatch

Insert or update multiple items in a single request. Endpoint: POST /<bucket> Request Body: JSON array of item objects Item Object Fields:
FieldRequiredDescription
pkYesPartition key
skYesSort key
ctNoCausality token from previous read (null for new items)
vNoBase64-encoded value (null for tombstone/delete)
Response: HTTP 204 NO CONTENT on success Example Request:
POST /my-bucket HTTP/1.1
Host: k2v.garage.example.com
Content-Type: application/json

[
  {
    "pk": "mailbox:INBOX",
    "sk": "001892831",
    "ct": "opaquetoken321",
    "v": "YjY0Y3J5cHRvYmxvYjMyMXVwZGF0ZWQ="
  },
  {
    "pk": "mailbox:INBOX",
    "sk": "001892912",
    "ct": null,
    "v": "YjY0Y3J5cHRvYmxvYjQ0NA=="
  },
  {
    "pk": "mailbox:INBOX",
    "sk": "001892932",
    "ct": "opaquetoken654",
    "v": null
  }
]
Example Response:
HTTP/1.1 204 NO CONTENT
Batch operations are not transactions. If the operation fails, some items may be inserted while others are not. Check the response status carefully.

DeleteBatch

Delete multiple items matching specified criteria. Endpoint: POST /<bucket>?delete Request Body: JSON array of query objects Query Object Fields:
FieldRequiredDefaultDescription
partitionKeyYes-Partition key to delete from
prefixNonullFilter sort keys by prefix
startNonullFirst sort key to delete
endNonullLast sort key to delete (exclusive)
singleItemNofalseDelete only item with sort key = start
Response: JSON array of result objects Result Object Fields:
FieldDescription
partitionKeyEcho of query partition key
prefix, start, endEcho of query parameters
singleItemEcho of query flag
deletedItemsNumber of items deleted
Example Request:
POST /my-bucket?delete HTTP/1.1
Host: k2v.garage.example.com
Content-Type: application/json

[
  {
    "partitionKey": "mailbox:OldMailbox"
  },
  {
    "partitionKey": "mailbox:INBOX",
    "start": "0018928321",
    "singleItem": true
  }
]
Example Response:
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "partitionKey": "mailbox:OldMailbox",
    "prefix": null,
    "start": null,
    "end": null,
    "singleItem": false,
    "deletedItems": 35
  },
  {
    "partitionKey": "mailbox:INBOX",
    "prefix": null,
    "start": "0018928321",
    "end": null,
    "singleItem": true,
    "deletedItems": 1
  }
]
DeleteBatch internally reads all matching items and creates deletion tombstones with causality tokens. You don’t need to provide causality tokens in the request.

PollRange

Wait for changes to items in a range. Endpoint: POST /<bucket>/<partition_key>?poll_range or SEARCH /<bucket>/<partition_key>?poll_range Request Body: JSON object Request Fields:
FieldRequiredDefaultDescription
prefixNonullFilter sort keys by prefix
startNonullFirst sort key to poll
endNonullLast sort key to poll (exclusive)
timeoutNo300Timeout in seconds (max 600)
seenMarkerNonullOpaque string from previous PollRange call
Response: HTTP 304 NOT MODIFIED (timeout), or HTTP 200 with JSON object Response Object Fields (when HTTP 200):
FieldDescription
seenMarkerOpaque string to use in future PollRange calls
itemsArray of changed items (same format as ReadBatch)
Example Request:
SEARCH /my-bucket/messages?poll_range HTTP/1.1
Host: k2v.garage.example.com
Content-Type: application/json

{
  "prefix": "2024-03-",
  "start": "2024-03-01",
  "seenMarker": "opaquestring123"
}
Example Response (Changes Detected):
HTTP/1.1 200 OK
Content-Type: application/json

{
  "seenMarker": "opaquestring456",
  "items": [
    {
      "sk": "2024-03-15-msg001",
      "ct": "opaquetoken123",
      "v": ["YjY0Y3J5cHRvYmxvYjEyMw=="]
    },
    {
      "sk": "2024-03-15-msg002",
      "ct": "opaquetoken456",
      "v": ["YjY0Y3J5cHRvYmxvYjQ1Ng=="]
    }
  ]
}
Example Response (No Changes):
HTTP/1.1 304 NOT MODIFIED
If you call PollRange without a seenMarker, it will return immediately with the current range contents and provide a marker for future calls. This is useful for initializing your polling state.

Index Operations

ReadIndex

List partition keys and get aggregate statistics. Endpoint: GET /<bucket> Query Parameters:
ParameterRequiredDefaultDescription
prefixNonullFilter partition keys by prefix
startNonullFirst partition key to list
endNonullLast partition key to list (exclusive)
limitNonullMaximum number of partition keys to return
reverseNofalseIterate in reverse order
Response: JSON object with partition key statistics Response Fields:
FieldDescription
prefix, start, end, limit, reverseEcho of query parameters
partitionKeysArray of partition key statistics
moreBoolean indicating more partition keys available
nextStartPartition key to use for next page (if more is true)
Partition Key Statistics:
FieldDescription
pkThe partition key
entriesNumber of triplets in this partition
conflictsNumber of triplets with conflicts
valuesTotal number of values (>= entries if conflicts exist)
bytesTotal bytes of all values
Example Request:
GET /my-bucket HTTP/1.1
Host: k2v.garage.example.com
Example Response:
HTTP/1.1 200 OK
Content-Type: application/json

{
  "prefix": null,
  "start": null,
  "end": null,
  "limit": null,
  "reverse": false,
  "partitionKeys": [
    {
      "pk": "keys",
      "entries": 3043,
      "conflicts": 0,
      "values": 3043,
      "bytes": 121720
    },
    {
      "pk": "mailbox:INBOX",
      "entries": 42,
      "conflicts": 1,
      "values": 43,
      "bytes": 142029
    },
    {
      "pk": "mailbox:Junk",
      "entries": 2991,
      "conflicts": 0,
      "values": 2991,
      "bytes": 12019322
    },
    {
      "pk": "mailbox:Trash",
      "entries": 10,
      "conflicts": 0,
      "values": 10,
      "bytes": 32401
    },
    {
      "pk": "mailboxes",
      "entries": 3,
      "conflicts": 0,
      "values": 3,
      "bytes": 3019
    }
  ],
  "more": false,
  "nextStart": null
}
Index statistics are eventually consistent. They are updated asynchronously, so the counts may lag behind actual values, especially for recently modified partitions.

Common Headers

Request Headers

HeaderUsed InDescription
X-Garage-Causality-TokenInsertItem, DeleteItemCausality token from previous read
AcceptReadItem, PollItemControls response format (JSON vs binary)
Content-TypeInsertBatch, ReadBatch, DeleteBatch, PollRangeShould be application/json for JSON requests

Response Headers

HeaderReturned ByDescription
X-Garage-Causality-TokenReadItem, PollItemCausality token for the current item state
Content-TypeAllMIME type of response body

Error Responses

Common HTTP error codes:
CodeNameDescription
400Bad RequestInvalid parameters or malformed request
404Not FoundItem or bucket not found
406Not AcceptableInvalid Accept header
409ConflictMultiple concurrent values when binary format requested
500Internal Server ErrorServer-side error (value may still be stored on some nodes)
HTTP 500 errors don’t guarantee the operation failed. Due to eventual consistency, the operation may succeed on some nodes even if quorum wasn’t reached. The value will propagate asynchronously.

Build docs developers (and LLMs) love