Skip to main content
Registration uploads the WASM component you built in Step 2 and gives it a tenant-local name. After this step, T3N knows about your contract and gives you a numeric contract_id that you use when creating map ACLs. Before you run this code, make sure you have:
  • An authenticated TenantClient named tenant. If you have not created one yet, complete step 4 and 5 of set up the dev environment first.
  • A compiled WASM file at target/wasm32-wasip2/release/your_contract.wasm.
  • Your tenantDid, for example did:t3n:abcdef0123456789abcdef0123456789abcdef01.

Choose a contract tail

The tail is the local name of your contract inside your tenant namespace. Pass only the part after z:<tid>:. For example, the tail travel/contracts becomes:
z:<tid>:travel/contracts
Do not include z:<tid>: in the tail; the SDK and host derive that from the authenticated tenant. Pick a stable tail for each contract you plan to maintain. When you register a new build at the same tail, increase the version value; changing the tail creates a separate contract entry.

Register the WASM

import { readFile } from "fs/promises";

const WASM_PATH = "target/wasm32-wasip2/release/your_contract.wasm";
const CONTRACT_TAIL = "travel/contracts";
const CONTRACT_VERSION = "0.1.0";

const wasmBytes = await readFile(WASM_PATH);

const result = await tenant.contracts.register({
  tail: CONTRACT_TAIL,
  version: CONTRACT_VERSION,
  wasm: wasmBytes,
});

// This numeric ID is required in the next setup step when you create map ACLs.
const contractId = result.contract_id;
const tenantId = tenantDid.slice("did:t3n:".length);
const scriptName = `z:${tenantId}:${CONTRACT_TAIL}`;

console.log(`registered ${scriptName} as contract id ${contractId}`);
Run this from the same repository root you used to build the contract. If your management script lives somewhere else, update WASM_PATH to point at the .wasm file.
Registration does not run your code, create maps, seed secrets, or grant outbound HTTP access. It only stores the component and records the versioned contract entry for your tenant.

What T3N stores

The register payload is just { tail, version, wasm }; there is no manifest. Host-side, T3N:
  1. Stores the WASM blob in content-addressed storage.
  2. Allocates a numeric ContractId.
  3. Records the contract under your tenant registry.
Your contract’s capabilities come from the host interfaces it imports in world.wit, not from this registration request. See Capabilities come from your WIT imports. Outbound hosts are also not declared here. They come from the calling user’s authorization grant at invoke time. See Outbound HTTP is authorized by the user, not the contract.

First-run troubleshooting

Error or symptomWhat it usually meansWhat to do
ENOENT: no such file or directoryThe WASM path is wrong, or the contract was not built yet.Re-run Step 2 and confirm the path with ls -lh target/wasm32-wasip2/release/*.wasm.
tenant not foundThe session DID does not match an admitted tenant — you constructed or derived tenantDid instead of reading it from the session.Read tenantDid from did.value after authenticating (see Step 5 in set up dev env), then rebuild TenantClient with it. Confirm with tenant.me().
version <x> is not higher than current version <y>You already registered this tail with the same or a higher version.Bump CONTRACT_VERSION, for example from 0.1.0 to 0.1.1.
The contract registers, but later cannot read secretsThe map does not exist yet, or its ACL does not include this contractId.Use the returned contractId when creating the secrets map ACLs.
The contract is now registered. It still cannot complete the full end-to-end flow until the maps and secrets it reads at runtime exist.