[{"data":1,"prerenderedAt":582},["ShallowReactive",2],{"docs:\u002Fdocs\u002Fconcepts":3,"docs:nav":534},{"id":4,"title":5,"badge":6,"body":7,"description":525,"extension":526,"meta":527,"navigation":528,"order":280,"path":529,"section":530,"seo":531,"stem":532,"__hash__":533},"docs\u002Fdocs\u002Fconcepts.md","Concepts & data model",null,{"type":8,"value":9,"toc":514},"minimark",[10,14,19,31,35,47,51,54,118,125,148,152,159,238,246,250,257,260,365,368,375,379,386,393,403,407,415,419,422,425,429,510],[11,12,13],"p",{},"The data model has four layers. It is worth ten minutes now, because every endpoint is shaped by\nit and none of it will make sense otherwise.",[15,16,18],"h2",{"id":17},"sector","Sector",[11,20,21,22,26,27,30],{},"The unit of storage a provider deals in: ",[23,24,25],"strong",{},"4 MiB",". Every sector is addressed by its ",[23,28,29],{},"Merkle\nroot",", a 32-byte hash. That root is how you ask for it back and how integrity is verified — a\nprovider that returns different bytes returns bytes that do not hash to the root you asked for, and\nyour client rejects them.",[15,32,34],{"id":33},"shard","Shard",[11,36,37,38,41,42,46],{},"One erasure-coded fragment of your data, stored as one or more sectors on one provider. With the\ndefault geometry a slab has ",[23,39,40],{},"15 shards: 10 data, 5 parity",". Shard size is\n",[43,44,45],"code",{},"ceil(sliceSize \u002F minShards)",".",[15,48,50],{"id":49},"slab","Slab",[11,52,53],{},"A slab is one erasure-coded stripe: a set of shards that decode together. It records:",[55,56,57,70],"table",{},[58,59,60],"thead",{},[61,62,63,67],"tr",{},[64,65,66],"th",{},"Field",[64,68,69],{},"Meaning",[71,72,73,88,98,108],"tbody",{},[61,74,75,81],{},[76,77,78],"td",{},[43,79,80],{},"minShards",[76,82,83,84,87],{},"How many shards are needed to reconstruct — ",[43,85,86],{},"10"," by default.",[61,89,90,95],{},[76,91,92],{},[43,93,94],{},"sectors[]",[76,96,97],{},"One entry per shard: the provider's public key, the sector root, and the contract.",[61,99,100,105],{},[76,101,102],{},[43,103,104],{},"encryptionKey",[76,106,107],{},"32 bytes of encryption parameter for this slab.",[61,109,110,115],{},[76,111,112],{},[43,113,114],{},"version",[76,116,117],{},"Slab format version.",[11,119,120,121,124],{},"A slab's ",[23,122,123],{},"ID is a content-addressed digest of its parameters"," — not a random identifier, and\nnotably not a hash of the provider set. That is deliberate: repair can move a shard to a different\nprovider without the slab ID changing, so your object references stay valid across repairs you\nnever see.",[126,127,130],"app-callout",{"title":128,"tone":129},"Slab geometry is validated","warn",[11,131,132,133,136,137,140,141,144,145,147],{},"Redundancy (",[43,134,135],{},"totalShards \u002F minShards",") must be at least ",[23,138,139],{},"1.5×"," and at most ",[23,142,143],{},"4.0×",". No provider\nmay appear twice in one slab, duplicate sector roots are rejected, and ",[43,146,104],{}," must be\nexactly 32 bytes. Violations are rejected at registration, not silently accepted.",[15,149,151],{"id":150},"object","Object",[11,153,154,155,158],{},"An object is an ",[23,156,157],{},"ordered list of slab segments",", plus wrapped key material and signatures:",[55,160,161,169],{},[58,162,163],{},[61,164,165,167],{},[64,166,66],{},[64,168,69],{},[71,170,171,181,194,204,214,224],{},[61,172,173,178],{},[76,174,175],{},[43,176,177],{},"id",[76,179,180],{},"32-byte object key. Usually a hash of the content; you choose it.",[61,182,183,188],{},[76,184,185],{},[43,186,187],{},"slabs[]",[76,189,190,193],{},[43,191,192],{},"{ id, offset, length }"," — a byte range within a slab. Concatenated in order, these are your object.",[61,195,196,201],{},[76,197,198],{},[43,199,200],{},"encryptedDataKey",[76,202,203],{},"The object's data key, wrapped. Tessera cannot unwrap it.",[61,205,206,211],{},[76,207,208],{},[43,209,210],{},"encryptedMetadata",[76,212,213],{},"An opaque blob. Anything you want. Tessera never interprets it.",[61,215,216,221],{},[76,217,218],{},[43,219,220],{},"encryptedMetadataKey",[76,222,223],{},"The wrapped key for that blob.",[61,225,226,235],{},[76,227,228,231,232],{},[43,229,230],{},"dataSignature",", ",[43,233,234],{},"metadataSignature",[76,236,237],{},"Your signatures over the respective parts.",[11,239,240,241,245],{},"Because an object is a list of slab ",[242,243,244],"em",{},"segments",", several small objects can share a slab, and one\nlarge object can span many. Deduplication and packing are consequences of the model rather than\nfeatures bolted onto it.",[15,247,249],{"id":248},"what-the-object-model-does-not-contain","What the object model does not contain",[11,251,252,253,256],{},"There is ",[23,254,255],{},"no filename, no path, no directory, no content type, and no cleartext size",". These are\nnot fields we decline to populate; the columns do not exist.",[11,258,259],{},"This is the single most important thing to understand before you integrate. If your application\nneeds a file browser, you build the naming layer:",[261,262,267],"pre",{"className":263,"code":264,"language":265,"meta":266,"style":266},"language-ts shiki shiki-themes github-dark-default github-dark-default","\u002F\u002F Your metadata blob, encrypted by you, opaque to us.\nconst metadata = {\n  name: 'quarterly-report.pdf',\n  contentType: 'application\u002Fpdf',\n  size: 8_431_233,\n  path: '\u002Freports\u002F2026\u002Fq1\u002F',\n  createdAt: '2026-04-02T09:14:00Z',\n}\n\u002F\u002F encrypt(metadata) → encryptedMetadata\n","ts","",[43,268,269,278,296,309,320,331,342,353,359],{"__ignoreMap":266},[270,271,274],"span",{"class":272,"line":273},"line",1,[270,275,277],{"class":276},"sI3U9","\u002F\u002F Your metadata blob, encrypted by you, opaque to us.\n",[270,279,281,285,289,292],{"class":272,"line":280},2,[270,282,284],{"class":283},"srH4v","const",[270,286,288],{"class":287},"sEQcL"," metadata",[270,290,291],{"class":283}," =",[270,293,295],{"class":294},"sb7RM"," {\n",[270,297,299,302,306],{"class":272,"line":298},3,[270,300,301],{"class":294},"  name: ",[270,303,305],{"class":304},"skZ57","'quarterly-report.pdf'",[270,307,308],{"class":294},",\n",[270,310,312,315,318],{"class":272,"line":311},4,[270,313,314],{"class":294},"  contentType: ",[270,316,317],{"class":304},"'application\u002Fpdf'",[270,319,308],{"class":294},[270,321,323,326,329],{"class":272,"line":322},5,[270,324,325],{"class":294},"  size: ",[270,327,328],{"class":287},"8_431_233",[270,330,308],{"class":294},[270,332,334,337,340],{"class":272,"line":333},6,[270,335,336],{"class":294},"  path: ",[270,338,339],{"class":304},"'\u002Freports\u002F2026\u002Fq1\u002F'",[270,341,308],{"class":294},[270,343,345,348,351],{"class":272,"line":344},7,[270,346,347],{"class":294},"  createdAt: ",[270,349,350],{"class":304},"'2026-04-02T09:14:00Z'",[270,352,308],{"class":294},[270,354,356],{"class":272,"line":355},8,[270,357,358],{"class":294},"}\n",[270,360,362],{"class":272,"line":361},9,[270,363,364],{"class":276},"\u002F\u002F encrypt(metadata) → encryptedMetadata\n",[11,366,367],{},"To list a directory you decrypt the metadata of the objects you know about, which means you keep a\nlocal index. The trade is explicit: you take on an index, and in exchange no one — including us,\nincluding anyone who compels us — can enumerate what you have stored or infer anything from its\nnames.",[126,369,372],{"title":370,"tone":371},"Design your keys deliberately","note",[11,373,374],{},"The object key is the only server-side handle you get, and you choose it. A content hash gives you\nfree deduplication. A deterministic hash of your own path gives you lookup by path without an\nindex. A random key gives you unlinkability. Pick before you have a million objects, not after.",[15,376,378],{"id":377},"account","Account",[11,380,381,382,385],{},"Your account is your ",[23,383,384],{},"credential"," — specifically the ed25519 public key you were issued. There is\nno separate account object, no username, and no email in the storage path.",[11,387,388,389,392],{},"Every slab and object is bound to the account that created it. A request signed by a different\ncredential is refused with ",[43,390,391],{},"403",", not silently emptied. Provisioning a new credential creates a new\nand entirely separate namespace; there is no notion of a credential belonging to an account that\nowns objects.",[126,394,396],{"title":395,"tone":129},"Consequence worth planning for",[11,397,398,399,402],{},"Because the credential ",[242,400,401],{},"is"," the account, losing the private key means losing access to everything\nstored under it, and we cannot restore it — we never had it. Treat the credential as you would a\nroot key: back it up before you store anything you care about.",[15,404,406],{"id":405},"how-the-layers-stack","How the layers stack",[261,408,413],{"className":409,"code":411,"language":412},[410],"language-text","Object  \"report.pdf\"        ← your metadata says so; we do not know\n  ├── slab A, offset 0,       length 4194304\n  └── slab B, offset 0,       length 4236929\n                 │\n                 └── Slab B: minShards 10, 15 sectors\n                       ├── shard  1 → provider ed25519:a1b2… root 9f3c…\n                       ├── shard  2 → provider ed25519:c3d4… root 22ab…\n                       ├── …\n                       └── shard 15 → provider ed25519:e5f6… root 7c1d…\n","text",[43,414,411],{"__ignoreMap":266},[15,416,418],{"id":417},"repair","Repair",[11,420,421],{},"Slab health is scanned continuously. When a shard's provider goes away, the slab is queued for\nrepair: the shard is reconstructed from parity and written to a replacement provider, and the slab\nrecord is updated in place. The slab ID does not change, so nothing referencing it breaks.",[11,423,424],{},"You do not trigger repair, pay for it as an event, or need to read the data for it to happen.",[15,426,428],{"id":427},"encoding-conventions","Encoding conventions",[55,430,431,441],{},[58,432,433],{},[61,434,435,438],{},[64,436,437],{},"Type",[64,439,440],{},"Wire format",[71,442,443,451,462,476,489,502],{},[61,444,445,448],{},[76,446,447],{},"Slab ID, object key, sector root",[76,449,450],{},"Lowercase hex, 64 characters",[61,452,453,456],{},[76,454,455],{},"Provider public key",[76,457,458,461],{},[43,459,460],{},"ed25519:"," followed by 64 hex characters",[61,463,464,469],{},[76,465,466,468],{},[43,467,384],{}," query parameter",[76,470,471,472,475],{},"base64url ",[23,473,474],{},"with"," padding",[61,477,478,484],{},[76,479,480,483],{},[43,481,482],{},"appKey"," from provisioning",[76,485,471,486,475],{},[23,487,488],{},"without",[61,490,491,499],{},[76,492,493,494,231,496,498],{},"Byte-slice JSON fields (",[43,495,104],{},[43,497,210],{},", …)",[76,500,501],{},"Standard base64 with padding",[61,503,504,507],{},[76,505,506],{},"Timestamps",[76,508,509],{},"RFC 3339",[511,512,513],"style",{},"html pre.shiki code .sI3U9, html code.shiki .sI3U9{--shiki-default:#8B949E;--shiki-dark:#8B949E}html pre.shiki code .srH4v, html code.shiki .srH4v{--shiki-default:#FF7B72;--shiki-dark:#FF7B72}html pre.shiki code .sEQcL, html code.shiki .sEQcL{--shiki-default:#79C0FF;--shiki-dark:#79C0FF}html pre.shiki code .sb7RM, html code.shiki .sb7RM{--shiki-default:#E6EDF3;--shiki-dark:#E6EDF3}html pre.shiki code .skZ57, html code.shiki .skZ57{--shiki-default:#A5D6FF;--shiki-dark:#A5D6FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":266,"searchDepth":298,"depth":298,"links":515},[516,517,518,519,520,521,522,523,524],{"id":17,"depth":280,"text":18},{"id":33,"depth":280,"text":34},{"id":49,"depth":280,"text":50},{"id":150,"depth":280,"text":151},{"id":248,"depth":280,"text":249},{"id":377,"depth":280,"text":378},{"id":405,"depth":280,"text":406},{"id":417,"depth":280,"text":418},{"id":427,"depth":280,"text":428},"Sectors, shards, slabs, objects, and accounts — what each one is, why the model has no filenames, and what that means for your integration.","md",{},true,"\u002Fdocs\u002Fconcepts","Introduction",{"title":5,"description":525},"docs\u002Fconcepts","6NprrFFyzlqViBxU2Q-y9fOgQ6sXN4XcYglnExuIRjs",[535,539,543,547,551,555,560,561,566,570,574,578],{"path":536,"title":378,"description":537,"section":538,"order":322,"badge":6},"\u002Fdocs\u002Fapi\u002Faccount","GET \u002Faccount — stored, read, and written byte counters for your credential.","API reference",{"path":540,"title":541,"description":542,"section":538,"order":311,"badge":6},"\u002Fdocs\u002Fapi\u002Fobjects","Objects","Register, read, list, and delete objects — ordered lists of slab segments with encrypted keys and opaque metadata.",{"path":544,"title":545,"description":546,"section":538,"order":280,"badge":6},"\u002Fdocs\u002Fapi\u002Fplacement","Placement","POST \u002Fprepare-write — get the providers, contracts, and access tokens for writing a slab's shards.",{"path":548,"title":549,"description":550,"section":538,"order":273,"badge":6},"\u002Fdocs\u002Fapi\u002Fprovisioning","Credentials","Provision, verify, and revoke the ed25519 credential that is both your API identity and your account.",{"path":552,"title":553,"description":554,"section":538,"order":298,"badge":6},"\u002Fdocs\u002Fapi\u002Fslabs","Slabs","Register, read, list, unpin, and prune erasure-coded slabs — the layer that records which provider holds which shard.",{"path":556,"title":557,"description":558,"section":559,"order":280,"badge":6},"\u002Fdocs\u002Fauthentication","Authentication","Every request is signed with ed25519 over a blake2b hash of the method, host, path, expiry, and body. Here is the exact construction, with working code.","Guides",{"path":529,"title":5,"description":525,"section":530,"order":280,"badge":6},{"path":562,"title":563,"description":564,"section":565,"order":273,"badge":6},"\u002Fdocs\u002Ferrors","Errors","Status codes, the two different error body formats, and the one case where a failure arrives with a 200.","Reference",{"path":567,"title":568,"description":569,"section":530,"order":273,"badge":6},"\u002Fdocs","Overview","Tessera is an HTTP API for storing encrypted, erasure-coded objects across independent storage providers. This is the reference for it.",{"path":571,"title":572,"description":573,"section":565,"order":280,"badge":6},"\u002Fdocs\u002Flimits","Limits & quotas","Rate limits, storage caps, geometry constraints, and the size and encoding limits that apply to every request.",{"path":575,"title":576,"description":577,"section":559,"order":273,"badge":6},"\u002Fdocs\u002Fquickstart","Quickstart","Provision a credential, upload an object across 15 providers, and read it back. Fifteen minutes, one file of code.",{"path":579,"title":580,"description":581,"section":559,"order":298,"badge":6},"\u002Fdocs\u002Frecovery","Recovery without Tessera","How to retrieve your data if Tessera is unavailable, unwilling, or permanently gone — and what you need to keep on hand for that to work.",1786190914109]