Skip to content

Learn how to create, update, delete, and extend entities on Arkiv using the TypeScript SDK’s wallet client.

All write operations require a wallet client:

import { createWalletClient, http } from "@arkiv-network/sdk"
import { privateKeyToAccount } from "@arkiv-network/sdk/accounts"
import { kaolin } from "@arkiv-network/sdk/chains"
const walletClient = createWalletClient({
chain: kaolin,
transport: http(),
account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),
})

Convert data to Arkiv payloads before storing:

import { jsonToPayload, stringToPayload, payloadToString } from "@arkiv-network/sdk/utils"
// JSON data
const jsonPayload = jsonToPayload({ title: "My Note", content: "Hello!" })
// Plain text
const textPayload = stringToPayload("Hello Arkiv!")
// Reading back
const text = payloadToString(entity.payload)
const data = entity.toJson()
import { jsonToPayload, ExpirationTime } from "@arkiv-network/sdk/utils"
const { entityKey, txHash } = await walletClient.createEntity({
payload: jsonToPayload({ title: "My Note", content: "Hello Arkiv!" }),
contentType: "application/json",
attributes: [
{ key: "type", value: "note" },
{ key: "id", value: crypto.randomUUID() },
{ key: "created", value: Date.now() },
],
expiresIn: ExpirationTime.fromHours(12),
})
console.log("Created:", entityKey)
FieldTypeDescription
payloadUint8ArrayEntity data (use jsonToPayload or stringToPayload)
contentTypestringMIME type (application/json, text/plain, etc.)
attributesArrayKey-value pairs for querying
expiresInnumberLifetime in seconds (use ExpirationTime helpers)
FieldTypeDescription
entityKeystringUnique identifier for the entity
txHashstringTransaction hash on the chain

Replace an entity’s payload, attributes, and expiration:

const { txHash } = await walletClient.updateEntity({
entityKey: entityKey,
payload: jsonToPayload({ title: "Updated Note", content: "New content" }),
contentType: "application/json",
attributes: [
{ key: "type", value: "note" },
{ key: "updated", value: Date.now() },
],
expiresIn: ExpirationTime.fromHours(24),
})
const { txHash } = await walletClient.deleteEntity({
entityKey: entityKey,
})

Transfer an entity to a new owner:

const { entityKey, txHash } = await walletClient.changeOwnership({
entityKey: entityKey,
newOwner: "0x1234567890abcdef1234567890abcdef12345678",
})
FieldTypeDescription
entityKeyHexKey of the entity to transfer
newOwnerHexAddress of the new owner
FieldTypeDescription
entityKeyHexKey of the transferred entity
txHashstringTransaction hash on the chain

Add more time to an entity before it expires:

const { txHash } = await walletClient.extendEntity({
entityKey: entityKey,
expiresIn: ExpirationTime.fromHours(1),
})

Create multiple entities in a single transaction using mutateEntities():

await walletClient.mutateEntities({
creates: [
{
payload: jsonToPayload({ content: "Item 1" }),
contentType: "application/json",
attributes: [{ key: "type", value: "item" }],
expiresIn: ExpirationTime.fromMinutes(30),
},
{
payload: jsonToPayload({ content: "Item 2" }),
contentType: "application/json",
attributes: [{ key: "type", value: "item" }],
expiresIn: ExpirationTime.fromMinutes(30),
},
],
})
const items = ["frontend", "backend", "devops"]
await walletClient.mutateEntities({
creates: items.map((skill) => ({
payload: jsonToPayload({ profileId: "alice-123", skill }),
contentType: "application/json",
attributes: [
{ key: "type", value: "skill" },
{ key: "profileId", value: "alice-123" },
{ key: "skill", value: skill },
],
expiresIn: ExpirationTime.fromDays(30),
})),
})

Always use the helper instead of raw numbers:

import { ExpirationTime } from "@arkiv-network/sdk/utils"
ExpirationTime.fromMinutes(30) // 1800 seconds
ExpirationTime.fromHours(1) // 3600 seconds
ExpirationTime.fromHours(12) // 43200 seconds
ExpirationTime.fromHours(24) // 86400 seconds
ExpirationTime.fromDays(7) // 604800 seconds

In browser applications, use MetaMask as the transport instead of a private key:

import { createWalletClient, custom } from "@arkiv-network/sdk"
import { kaolin } from "@arkiv-network/sdk/chains"
// Request wallet connection
await window.ethereum.request({ method: 'eth_requestAccounts' })
// Use MetaMask as transport
const walletClient = createWalletClient({
chain: kaolin,
transport: custom(window.ethereum),
})

See the MetaMask Sketch App tutorial for a complete browser example.

The SDK does not retry on failure — all methods throw on error. Wrap write operations in try/catch:

try {
const { entityKey, txHash } = await walletClient.createEntity({
payload: jsonToPayload({ title: "My Post" }),
contentType: "application/json",
attributes: [{ key: "type", value: "post" }],
expiresIn: ExpirationTime.fromHours(12),
})
} catch (error) {
// Common failures:
// - User rejected the transaction (MetaMask popup dismissed)
// - Insufficient funds / gas
// - Network error (RPC unreachable)
// - Entity already expired (for update/extend)
console.error("Transaction failed:", error)
}