When an agent stores data on Walrus, or receives a blob ID and plans to build on it, it needs to confirm the data is durably stored before depending on it. The authoritative signal is Walrus state recorded on Sui: a certified, unexpired, non-deletable `Blob` object, or a verified blob-status result backed by the onchain certification event. A write call returning or an aggregator read succeeding is not enough. This page describes the verify-before-act pattern and the checks to run.

## What durable storage means on Walrus

In the standard store path, Walrus represents each stored blob as a Sui object of type `Blob`, paired with a `Storage` object that reserves space for a fixed period. A blob moves through two states: registered, where storage nodes expect its slivers, and certified, where enough slivers are stored to guarantee availability. A blob is safe to depend on only after it is certified, and only until its storage period ends.

The `Blob` and `Storage` objects expose fields you can read from Sui:

```move
/// Reservation for storage for a given period, inclusive start, exclusive end.
public struct Storage has key, store {
    id: UID,
    start_epoch: u32,
    end_epoch: u32,
    storage_size: u64,
}

public struct Blob has key, store {
    id: UID,
    registered_epoch: u32,
    blob_id: u256,
    size: u64,
    encoding_type: u8,
    certified_epoch: option::Option<u32>, // set to the epoch first certified, if any
    storage: Storage,
    deletable: bool, // whether the owner can delete the blob before expiry
}
```

## Why verify before acting

Several signals look like confirmation but do not prove durability:

- A write call returning, or an HTTP 200 from a publisher, reports that a request was accepted, not that the blob is certified and remains available.
- An aggregator read can return a stale cached 404 right after certification, or succeed only because another copy exists that you do not control.
- A blob expires at the end of its storage period, and a deletable blob can be removed by its owner before then.

Depending on a blob without reading the chain risks building on data that is not yet certified, has expired, or can disappear.

> **Caution**
>
> Do not treat an immediate aggregator 404 as proof the blob is missing. Right after certification, a cache in front of the aggregator might still serve a stale 404. Confirm against Sui state, or retry the read with backoff.
## The check

Before you depend on a blob, confirm all three conditions. If you have the `Blob` object ID, read that object directly from Sui:

- **Certified:** `certified_epoch` is set, so the blob reached the certified state.
- **Within its storage period:** the current epoch is less than `storage.end_epoch`. Require enough epochs of margin for how long you need the data.
- **Not deletable, when you need persistence:** `deletable` is `false`, so the owner cannot remove the blob before it expires.

A certified, non-deletable `Blob` object looks like this when read as JSON:

```json
{
  "id": "0xe91eee8c5b6f35b9a250cfc29e30f0d9e5463a21fd8d1ddb0fc22d44db4eac50",
  "registeredEpoch": 34,
  "blobId": "M4hsZGQ1oCktdzegB6HnI6Mi28S2nqOPHxK-W7_4BUk",
  "size": 17,
  "encodingType": "RS2",
  "certifiedEpoch": 34,
  "storage": { "startEpoch": 34, "endEpoch": 35, "storageSize": 66034000 },
  "deletable": false
}
```

Here `certifiedEpoch` is set, `endEpoch` is 35, and `deletable` is `false`, so the blob is safe to depend on while the current epoch is below 35.

## Tooling

Check a blob by its ID with the CLI:

```
$ walrus blob-status --blob-id <BLOB_ID>
```

This reports whether the blob is stored and its availability period. When it reports a certified permanent blob, it also returns the related Sui event ID, a transaction ID and a sequence number. Read the current epoch with `walrus info`.

To check programmatically after writing a blob, use the `Blob` object ID from the write result and re-read that object from Sui before depending on it. The TypeScript SDK's `getBlobObject` helper reads the object over gRPC and returns the parsed Move struct. For the client construction, see the [Network Reference](/docs/network-reference#typescript-sdk).

```ts
const blob = await walrusClient.getBlobObject(blobObjectId); // blobObject.id from the write result

// certified_epoch is a parsed Move Option<u32>: null until the blob is certified.
const certified = blob.certified_epoch != null;
const endEpoch = blob.storage.end_epoch;

const durable = certified && currentEpoch < endEpoch && !blob.deletable;
if (!durable) {
  throw new Error("Blob is not durably available yet; do not depend on it");
}
```

For trustless or offline checks, authenticate the `BlobCertified` event or the `Blob` object through the Sui client, which returns signed evidence usable as a portable proof of availability. A Sui smart contract can run the same certified, before-expiry, and not-deletable check when the `Blob` object is passed as an input. See the `blob` and `storage_resource` Move modules for the field accessors.

## Verify integrity

Availability tells you a blob is still stored. Integrity tells you the bytes you read are the bytes
the writer committed. The link between the two is the `blob_id` field on the `Blob` object: a blob
ID is a commitment to the content, so a given blob ID always corresponds to the same bytes.
Verifying integrity means confirming the data you read matches the commitment recorded onchain. Two
layers give you that guarantee:

- **Aggregator consistency checks.** When you read through an aggregator, it checks that the slivers
  it returns are consistent with the blob's encoding before serving the bytes. The default check is
  sufficient for most cases. For a full check, add the query parameter `strict_consistency_check=true`.
  Only add `skip_consistency_check=true` when the writer is known and trusted. See
  [reading blobs over HTTP](/docs/http-api/reading-blobs#consistency-checks).
- **Binding to the onchain object.** Read the bytes
  [by object ID](/docs/http-api/reading-blobs#reading-by-object-id), so the data you fetch is tied to
  the specific `Blob` object whose certification and storage period you verified, not just to any
  certificate that happens to exist for the content.

For an offline or trustless check, the TypeScript SDK can re-encode content locally and derive its
blob ID, which you then compare against the `blob_id` on the `Blob` object. A match proves the bytes
are the committed content without trusting the aggregator. Note that the `blob_id` field read from
the Sui object is a `u256` value, not the base64 blob ID used in aggregator URLs, so read by object
ID rather than splicing that field into a read URL.

## Worked example: availability and integrity

The following function takes a `Blob` object ID, confirms the blob is durable, then reads the bytes
through an aggregator with the consistency check enabled. It returns the verified bytes, or throws
if any check fails. Set `aggregator` to an endpoint from the
[Network Reference](/docs/network-reference#aggregators-and-publishers), and read the current epoch
with `walrus info` or from Walrus system state.

```ts
import { WalrusClient } from "@mysten/walrus";

async function readVerifiedBlob(
  walrusClient: WalrusClient,
  aggregator: string,
  blobObjectId: string,
  currentEpoch: number,
): Promise<Uint8Array> {
  // 1. Read the Blob object from Sui.
  const blob = await walrusClient.getBlobObject(blobObjectId);

  // 2. Check availability: certified, within its storage period, not deletable.
  const durable =
    blob.certified_epoch != null &&
    currentEpoch < blob.storage.end_epoch &&
    !blob.deletable;
  if (!durable) {
    throw new Error("Blob is not durably available; do not depend on it");
  }

  // 3. Read the bytes bound to this object, with the strict consistency check.
  const url = `${aggregator}/v1/blobs/by-object-id/${blobObjectId}?strict_consistency_check=true`;
  const read = await fetch(url);
  if (!read.ok) {
    // A CDN-fronted aggregator might serve a stale 404 right after certification.
    throw new Error(`Read failed with status ${read.status}; retry with backoff`);
  }

  return new Uint8Array(await read.arrayBuffer());
}
```

This binds every step to onchain state: the object read proves certification and the storage
window, and the aggregator read uses that same object and validates the encoding before returning
the bytes.

## Caveats

- Mainnet epochs last 2 weeks, so `end_epoch` gives a concrete time horizon for how long the data is guaranteed.
- A blob ID is derived from content, so identical content always produces the same blob ID, and multiple `Blob` objects can certify it. Verifying by blob ID confirms that some non-expired certificate exists, not that your specific object is the one keeping it alive. If you need ownership or accounting guarantees, verify the specific object ID too.
- Walrus blobs are public. Encrypt sensitive data, for example with Seal, before you store it.