Narrative Protocol

Quickstart

Get started with Narrative Protocol in 5 minutes

Quickstart

This guide walks through creating a world, defining schemas and events, running a deployment, and executing an event.

Prerequisites

Set your base API URL to https://api.narrativeprotocol.com.

Getting an API key

Before making API calls, create an API key in https://studio.narrativeprotocol.com. You will use this key in the Authorization header for all /api/* requests.


Blueprint Layer

The Blueprint layer is where you define your world structure. This includes creating worlds, entity schemas with attributes, and events with versioned behavior. These definitions are separate from runtime execution.

Step 1: Create your world

A world is the top-level container for your simulation. It holds entities, events, and can have multiple deployments. The promptSeed helps the AI understand your world context.

curl -X POST https://api.narrativeprotocol.com/api/worlds \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your-token>" \
  -d '{
    "name": "Horse Racing",
    "description": "A horse racing simulation world",
    "domainTags": ["sports", "simulation"],
    "promptSeed": "This world simulates realistic horse racing events."
  }'
const response = await fetch(`https://api.narrativeprotocol.com/api/worlds`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer <your-token>"
  },
  body: JSON.stringify({
    name: "Horse Racing",
    description: "A horse racing simulation world",
    domainTags: ["sports", "simulation"],
    promptSeed: "This world simulates realistic horse racing events."
  })
});
console.log(await response.json());
import requests

response = requests.post(
    "https://api.narrativeprotocol.com/api/worlds",
    headers={
        "Content-Type": "application/json",
        "Authorization": "Bearer <your-token>"
    },
    json={
        "name": "Horse Racing",
        "description": "A horse racing simulation world",
        "domainTags": ["sports", "simulation"],
        "promptSeed": "This world simulates realistic horse racing events."
    }
)
print(response.json())

Response

{
  "success": true,
  "data": {
    "id": 39,
    "address": "0xd36f777a077ff3825653f6d521f1437b4da69699",
    "userId": 746631,
    "name": "Horse Racing",
    "description": "A horse racing simulation world",
    "domainTags": ["sports", "simulation"],
    "promptSeed": "This world simulates realistic horse racing events.",
    "isPublic": false,
    "createdAt": "2026-02-18T04:13:02.315Z",
    "updatedAt": "2026-02-18T04:13:02.315Z"
  }
}

Step 2: Define an entity schema

An Entity Schema defines the structure for entities in your world. For example, a "horse" schema defines what attributes (name, speed, wins) all horses will have. You can define attributes during entity schema creation, including type, constraints, and defaultValue.

Attribute type values:

  • string
  • integer
  • float
  • boolean
  • json

Attribute constraints fields:

  • min (number)
  • max (number)
  • enum (string array)
curl -X POST https://api.narrativeprotocol.com/api/worlds/<world-address>/entity-schemas \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your-token>" \
  -d '{
    "name": "horse",
    "description": "A racing horse",
    "attributes": [
      {
        "name": "speed_rating",
        "type": "float",
        "constraints": { "min": 0, "max": 1 },
        "defaultValue": 0.5
      },
      {
        "name": "wins",
        "type": "integer",
        "constraints": { "min": 0 },
        "defaultValue": 0
      }
    ]
  }'
const response = await fetch(`https://api.narrativeprotocol.com/api/worlds/<world-address>/entity-schemas`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer <your-token>"
  },
  body: JSON.stringify({
    name: "horse",
    description: "A racing horse",
    attributes: [
      {
        name: "speed_rating",
        type: "float",
        constraints: { min: 0, max: 1 },
        defaultValue: 0.5
      },
      {
        name: "wins",
        type: "integer",
        constraints: { min: 0 },
        defaultValue: 0
      }
    ]
  })
});
console.log(await response.json());
import requests

response = requests.post(
    "https://api.narrativeprotocol.com/api/worlds/<world-address>/entity-schemas",
    headers={
        "Content-Type": "application/json",
        "Authorization": "Bearer <your-token>"
    },
    json={
        "name": "horse",
        "description": "A racing horse",
        "attributes": [
            {
                "name": "speed_rating",
                "type": "float",
                "constraints": { "min": 0, "max": 1 },
                "defaultValue": 0.5
            },
            {
                "name": "wins",
                "type": "integer",
                "constraints": { "min": 0 },
                "defaultValue": 0
            }
        ]
    }
)
print(response.json())

Response

{
  "success": true,
  "data": {
    "id": 53,
    "worldId": 39,
    "name": "horse",
    "description": "A racing horse",
    "createdAt": "2026-02-18T04:13:49.117Z",
    "updatedAt": "2026-02-18T04:13:49.117Z",
    "attributes": [
      {
        "name": "speed_rating",
        "type": "float",
        "constraints": { "min": 0, "max": 1 },
        "defaultValue": 0.5
      },
      {
        "name": "wins",
        "type": "integer",
        "constraints": { "min": 0 },
        "defaultValue": 0
      }
    ]
  }
}

Step 3: Create an event

Events define what can happen in your world.

firstVersion fields:

  • inputSchema: Defines the input payload expected at execution time.
  • readEntities: Lists entity schemas the event can read.
  • stateChangeSchema: Per-schema mutation mode (partial, full, append). partial merges into existing state, full replaces state, and append appends to arrays.
  • outputSchema: Defines the expected public result fields.
  • mutationSettings: Execution mode config (ai or direct; direct uses a template). When mode is ai, behaviorPrompt is required. When mode is direct, template is required.
  • executionSettings: Execution visibility and triggers (admin, public, cron) with optional priceUsd and cron config.

For more details, see Events.

curl -X POST https://api.narrativeprotocol.com/api/worlds/<world-address>/events \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your-token>" \
  -d '{
    "name": "race_result",
    "description": "Resolves a race and updates horse stats",
    "firstVersion": {
      "inputSchema": { "raceId": "string" },
      "readEntities": [{ "schema": "horse" }],
      "stateChangeSchema": { "horse": "partial" },
      "outputSchema": { "winner": "string", "time": "string" },
      "mutationSettings": {
        "mode": "ai",
        "behaviorPrompt": "Determine the race winner based on horse speed ratings. Update the winner's wins count."
      }
    }
  }'
const response = await fetch(`https://api.narrativeprotocol.com/api/worlds/<world-address>/events`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer <your-token>"
  },
  body: JSON.stringify({
    name: "race_result",
    description: "Resolves a race and updates horse stats",
    firstVersion: {
      inputSchema: { raceId: "string" },
      readEntities: [{ schema: "horse" }],
      stateChangeSchema: { horse: "partial" },
      outputSchema: { winner: "string", time: "string" },
      mutationSettings: {
        mode: "ai",
        behaviorPrompt: "Determine the race winner based on horse speed ratings. Update the winner's wins count."
      }
    }
  })
});
console.log(await response.json());
import requests

response = requests.post(
    "https://api.narrativeprotocol.com/api/worlds/<world-address>/events",
    headers={
        "Content-Type": "application/json",
        "Authorization": "Bearer <your-token>"
    },
    json={
        "name": "race_result",
        "description": "Resolves a race and updates horse stats",
        "firstVersion": {
            "inputSchema": { "raceId": "string" },
            "readEntities": [{ "schema": "horse" }],
            "stateChangeSchema": { "horse": "partial" },
            "outputSchema": { "winner": "string", "time": "string" },
            "mutationSettings": {
                "mode": "ai",
                "behaviorPrompt": "Determine the race winner based on horse speed ratings. Update the winner's wins count."
            }
        }
    }
)
print(response.json())

Live Layer

The Live layer is where your simulation actually runs. Deployments are isolated runtime instances of a world.

Step 4: Create a deployment

A deployment is a running instance of a world with its own isolated state.

curl -X POST https://api.narrativeprotocol.com/api/worlds/<world-address>/deployments \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your-token>" \
  -d '{
    "name": "Season 1",
    "bindings": [{
      "event": <event-name>,
      "eventVersion": <event-version>,
      "targetChains": ["near-testnet"]
    }]
  }'
const response = await fetch(`https://api.narrativeprotocol.com/api/worlds/<world-address>/deployments`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer <your-token>"
  },
  body: JSON.stringify({
    name: "Season 1",
    bindings: [{
      event: <event-name>,
      eventVersion: <event-version>,
      targetChains: ["near-testnet"]
    }]
  })
});
console.log(await response.json());
import requests

response = requests.post(
    "https://api.narrativeprotocol.com/api/worlds/<world-address>/deployments",
    headers={
        "Content-Type": "application/json",
        "Authorization": "Bearer <your-token>"
    },
    json={
        "name": "Season 1",
        "bindings": [{
            "event": <event-name>,
            "eventVersion": <event-version>,
            "targetChains": ["near-testnet"]
        }]
    }
)
print(response.json())

The targetChains option on each binding determines where event data for that event is stored on-chain:

  • [] - No on-chain storage (default)
  • ["solana-devnet"] - Push to Solana devnet
  • ["near-testnet"] - Push to NEAR testnet
  • ["solana-devnet", "near-testnet"] - Push to both chains

Step 5: Create entity instances

Entity instances are the actual data in your deployment.

curl -X POST https://api.narrativeprotocol.com/api/worlds/<world-address>/deployments/<deployment-address>/entity-instances \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your-token>" \
  -d '{
    "entitySchema": "horse",
    "instanceId": "HORSE_1",
    "state": {
      "name": "Midnight Comet",
      "speed_rating": 0.85
    }
  }'
const response = await fetch(`https://api.narrativeprotocol.com/api/worlds/<world-address>/deployments/<deployment-address>/entity-instances`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer <your-token>"
  },
  body: JSON.stringify({
    entitySchema: "horse",
    instanceId: "HORSE_1",
    state: {
      name: "Midnight Comet",
      speed_rating: 0.85
    }
  })
});
console.log(await response.json());
import requests

response = requests.post(
    "https://api.narrativeprotocol.com/api/worlds/<world-address>/deployments/<deployment-address>/entity-instances",
    headers={
        "Content-Type": "application/json",
        "Authorization": "Bearer <your-token>"
    },
    json={
        "entitySchema": "horse",
        "instanceId": "HORSE_1",
        "state": {
            "name": "Midnight Comet",
            "speed_rating": 0.85
        }
    }
)
print(response.json())

Step 6: Execute an event

Executing an event triggers the AI engine and applies state changes to your deployment.

curl -X POST https://api.narrativeprotocol.com/api/worlds/<world-address>/deployments/<deployment-address>/execute \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your-token>" \
  -d '{
    "event": <event-name>,
    "input": { "raceId": "RACE_001" }
  }'
const response = await fetch(`https://api.narrativeprotocol.com/api/worlds/<world-address>/deployments/<deployment-address>/execute`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer <your-token>"
  },
  body: JSON.stringify({
    event: <event-name>,
    input: { raceId: "RACE_001" }
  })
});
console.log(await response.json());
import requests

response = requests.post(
    f"https://api.narrativeprotocol.com/api/worlds/<world-address>/deployments/<deployment-address>/execute",
    headers={
        "Content-Type": "application/json",
        "Authorization": "Bearer <your-token>"
    },
    json={
        "event": <event-name>,
        "input": { "raceId": "RACE_001" }
    }
)
print(response.json())

Response

{
  "success": true,
  "data": {
    "historyId": 11133,
    "eventVersion": 1,
    "stateChanges": {
      "horse:HORSE_1": {
        "wins": 1
      }
    },
    "result": {
      "time": "2026-02-18T00:00:00Z",
      "winner": "Midnight Comet"
    },
    "attestation": {
      "signature": "0x0b09aa672cde45034a1091532b1e7f7e31b476181fd06ca4faafc566245a823f3ff0e8a65afd102b64a1370170e5819f242480e727d449cbdcc338d7324b9a191c",
      "signing_address": "0xbBC409e6b529817D257aD61D5738D8e3a39b5791",
      "signing_algo": "ecdsa",
      "text": "d3fc5ada116a1c0c9359ea6b7297b210cfecd393facc04c5d20209002a2dd126:ad558a6182aa4c55374cbd5eae218d6b2dae1957780630ecc6a0f01e49214af9"
    },
    "oracle": {
      "solana": null,
      "near": {
        "txHash": "8LjP9sqX26oQgScPy5RGzs8dEzwZiNSQHKrTpCLrP5yy",
        "receiptId": "ZWsNXEXPp1KyQWB68psjypi1PHGjMC8MrAomHBQLpGr"
      }
    }
  }
}

Step 7: View updated state

After executing an event, you can query the entity instances to see how the state has changed.

curl https://api.narrativeprotocol.com/api/worlds/<world-address>/deployments/<deployment-address>/entity-instances \
  -H "Authorization: Bearer <your-token>"
const response = await fetch(`https://api.narrativeprotocol.com/api/worlds/<world-address>/deployments/<deployment-address>/entity-instances`, {
  headers: {
    "Authorization": "Bearer <your-token>"
  }
});
console.log(await response.json());
import requests

response = requests.get(
    f"https://api.narrativeprotocol.com/api/worlds/<world-address>/deployments/<deployment-address>/entity-instances",
    headers={
        "Authorization": "Bearer <your-token>"
    }
)
print(response.json())

Next Steps