Sigil’s NFTs are native — there is no ERC-721 contract to deploy. CreateNftCollection opens the namespace, MintNft issues a token, TransferNft moves it. Identity collections additionally bind each token to a DID for credentialing.

When to use this

  • Issue badges, certificates, or proofs of attendance.
  • Mint identity-bound credentials that cannot leave their owner DID.
  • Tokenise rights to digital or physical assets.

Prerequisites

  • A funded controller DID for the new collection.
  • A metadata document hosted on IPFS or another content-addressed store.

Recipe

1

Create the collection

Standard collections are transferable. Identity collections bind each token to a DID at mint time and reject TransferNft for that token.
await signAndSend({
  CreateNftCollection: {
    collection_id: 'col:demo:badges',
    name: 'Demo Builder Badges',
    symbol: 'DBB',
    kind: 'Standard',           // or 'Identity'
    issuer_did: process.env.SIGIL_SENDER_DID,
    controller_did: process.env.SIGIL_SENDER_DID,
    policy: {
      max_supply: 1000,
      default_locked: false,
      default_burn_auth: 'Holder',  // 'Issuer' | 'Holder' | 'Both'
      mint_authority: 'Controller',
    },
    metadata_uri: 'ipfs://bafkrei.../collection.json',
  },
});
2

Mint a token

Token ids are 128-bit decimals on the wire. Use a deterministic source (e.g. an off-chain counter or a hash of the recipient) to avoid collisions.
await signAndSend({
  MintNft: {
    collection_id: 'col:demo:badges',
    token_id: '1',
    recipient_did: 'did:oas:sigil:agent:builder...',
    metadata_uri: 'ipfs://bafkrei.../token-1.json',
    metadata_hash: null,           // optional BLAKE3 of metadata document
    locked: false,
    burn_auth: null,               // null = inherit from collection
    identity: null,                // required when kind == 'Identity'
  },
});
For an identity collection, set identity:
"identity": {
  "subject_did": "did:oas:sigil:agent:builder...",
  "schema_uri": "ipfs://bafkrei.../badge-schema.json",
  "verification_level": "L1"
}
3

Transfer (standard collections only)

await signAndSend({
  TransferNft: {
    collection_id: 'col:demo:badges',
    token_id: '1',
    recipient_did: 'did:oas:sigil:agent:new-owner...',
  },
});
Identity tokens reject this transaction.

Reading state

# Look up a specific token
curl -s "$SIGIL_RPC_URL" \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"sigil_getNftToken",
       "params":{"collection_id":"col:demo:badges","token_id":"1"}}'

# List every NFT a DID owns
curl -s "$SIGIL_RPC_URL" \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"sigil_getOwnerNfts",
       "params":{"owner_did":"did:oas:sigil:agent:builder..."}}'

# For identity NFTs, look up by subject DID
curl -s "$SIGIL_RPC_URL" \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"sigil_getDidIdentityNft",
       "params":{"did":"did:oas:sigil:agent:builder..."}}'

Common errors

SymptomCauseFix
collection_id already existsReused idChoose a unique id
token_id already mintedDuplicate tokenPick a different token id
identity binding requiredIdentity collection without identity fieldAdd the IdentityBinding payload
transfer of identity NFT deniedTried to TransferNft an identity tokenIdentity tokens are soulbound by design
mint authority not satisfiedSender ≠ controller (or whichever authority is set)Submit from the configured mint authority

See also