> ## Documentation Index
> Fetch the complete documentation index at: https://docs.story.foundation/llms.txt
> Use this file to discover all available pages before exploring further.

# 📝 IPA Metadata Standard

> An overview of the IP-specific metadata standard

<Warning>
  We are still figuring out the best way to define an IPA Metadata Standard. For
  the sake of transparency, the following document is our thoughts so far but is
  subject to change as we release future versions.
</Warning>

<CardGroup cols={2}>
  <Card title="Official Ippy IP" href="https://explorer.story.foundation/ipa/0xB1D831271A68Db5c18c8F0B69327446f7C8D0A42" icon="house">
    Check out the official Ippy IP, which has both NFT & IP metadata.
  </Card>

  <Card title="How to Add Metadata to an IP Asset" href="/concepts/ip-asset/overview#nft-vs-ip-metadata" icon="computer">
    Learn how to actually add the IP metadata discussed here to your IP Asset with an explanation or completed code example.
  </Card>
</CardGroup>

This is the JSON metadata that is associated with an IP Asset, and gets stored inside of an IP Account. You must call `setMetadata(...)` inside of the IP Account in order to set the metadata, and then call `metadata()` to read it.

## Attributes & Structure

Below are the important attributes you should provide in your IP metadata. Under the **Required For** column is what the specific field is required for:

* 🔍 Story Explorer - this field will help display your IP on the Story Explorer
* 🕵️ [Commercial Infringement Check](/concepts/story-attestation-service) - this field is required if your IP is **commercial** (that is, has `commercialUse = true` license terms attached). We will use these fields to run an infringement check on your IP.
  * See [current limitations](/concepts/story-attestation-service#current-limitations).
* 🤖 AI Agents - used for displaying metadata associated with AI Agents

| Property Name | Type          | Description                                                                                                                                                                                     | Required For                                                             |
| ------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `title`       | `string`      | Title of the IP                                                                                                                                                                                 | 🔍 Story Explorer                                                        |
| `description` | `string`      | Description of the IP                                                                                                                                                                           | 🔍 Story Explorer                                                        |
| `createdAt`   | `string`      | Date/Time that the IP was created (either ISO8601 or unix format). This field can be used to specify historical dates that aren't on-chain. For example, Harry Potter was published on June 26. | 🔍 Story Explorer                                                        |
| `image`       | `string`      | An image for your IP. **For audio assets, the recommended thumbnail aspect ratio is 1:1. For video assets, it is 16:9.**                                                                        | 🔍 Story Explorer                                                        |
| `imageHash`   | `string`      | Hash of your `image` using SHA-256 hashing algorithm. See [here](#hashing-content) for how that is done.                                                                                        | 🔍 Story Explorer                                                        |
| `creators`    | `IpCreator[]` | An array of information about the creators. [See the type defined below](#type-definitions)                                                                                                     | 🔍 Story Explorer                                                        |
| `mediaUrl`    | `string`      | Used for infringement checking, points to the actual media (ex. image or audio). **For audio assets, the recommended thumbnail aspect ratio is 1:1. For video assets, it is 16:9.**             | 🕵️ [Commercial Infringement Check](/concepts/story-attestation-service) |
| `mediaHash`   | `string`      | Hashed string of the media using SHA-256 hashing algorithm. See [here](#hashing-content) for how that is done.                                                                                  | 🕵️ [Commercial Infringement Check](/concepts/story-attestation-service) |
| `mediaType`   | `string`      | Type of media (audio, video, image), based on [mimeType](https://developer.mozilla.org/en-US/docs/Web/HTTP/MIME_types/Common_types). See the allowed media types [here](#media-types).          | 🕵️ [Commercial Infringement Check](/concepts/story-attestation-service) |
| `aiMetadata`  | `AIMetadata`  | Used for registering & displaying AI Agent Metadata. [See the type defined below](#type-definitions)                                                                                            | 🤖 AI Agents                                                             |
| N/A           | N/A           | You can include other values as well.                                                                                                                                                           | N/A                                                                      |

### Type Definitions

Here are the type definitions for the complex types used in the metadata:

<CodeGroup>
  ```typescript IpCreator theme={null}
  type IpCreator = {
    name: string;
    address: Address;
    contributionPercent: number; // add up to 100
    description?: string;
    image?: string;
    socialMedia?: IpCreatorSocial[];
    role?: string;
  };

  type IpCreatorSocial = {
    platform: string;
    url: string;
  };
  ```

  ```typescript AIMetadata theme={null}
  type AIMetadata = {
    // this can be any character file you want
    // example: https://github.com/elizaOS/characterfile/blob/main/examples/example.character.json
    characterFileUrl: string;
    characterFileHash: string;
  };
  ```
</CodeGroup>

### Media Types

The following media types are allowed for the `mediaType` field:

| Media Type        | Description           |
| ----------------- | --------------------- |
| `image/jpeg`      | JPEG image            |
| `image/png`       | PNG image             |
| `image/apng`      | Animated PNG image    |
| `image/avif`      | AV1 Image File Format |
| `image/gif`       | GIF image             |
| `image/svg+xml`   | SVG image             |
| `image/webp`      | WebP image            |
| `audio/wav`       | WAV audio             |
| `audio/mpeg`      | MP3 audio             |
| `audio/flac`      | FLAC audio            |
| `audio/aac`       | AAC audio             |
| `audio/ogg`       | OGG audio             |
| `audio/mp4`       | MP4 audio             |
| `audio/x-aiff`    | AIFF audio            |
| `audio/x-ms-wma`  | WMA audio             |
| `audio/opus`      | Opus audio            |
| `video/mp4`       | MP4 video             |
| `video/webm`      | WebM video            |
| `video/quicktime` | QuickTime video       |

### Hashing Content

To hash content for the `imageHash` or `mediaHash` fields, you can use the SHA-256 hashing algorithm. Here's an example of how to do this in JavaScript:

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { toHex, Hex } from "viem";

  // get hash from a file
  async function getFileHash(file: File): Promise<Hex> {
    const arrayBuffer = await file.arrayBuffer();
    const hashBuffer = await crypto.subtle.digest("SHA-256", arrayBuffer);
    return toHex(new Uint8Array(hashBuffer), { size: 32 });
  }

  // get hash from a url
  async function getHashFromUrl(url: string): Promise<Hex> {
    const response = await axios.get(url, { responseType: "arraybuffer" });
    const buffer = Buffer.from(response.data);
    return "0x" + createHash("sha256").update(buffer).digest("hex");
  }
  ```

  ```shell Shell theme={null}
  shasum -a 256 myfile.jpg
  ```
</CodeGroup>

### Example Use Cases

<Tabs>
  <Tab title="Ippy Mascot">
    This is the official Ippy mascot that is registered on mainnet. You can view it on our protocol explorer [here](https://explorer.story.foundation/ipa/0xB1D831271A68Db5c18c8F0B69327446f7C8D0A42).

    ```json theme={null}
    {
      "title": "Ippy",
      "description": "Official mascot of Story.",
      "createdAt": "1728401700",
      "image": "https://ipfs.io/ipfs/QmSamy4zqP91X42k6wS7kLJQVzuYJuW2EN94couPaq82A8",
      "imageHash": "0x21937ba9d821cb0306c7f1a1a2cc5a257509f228ea6abccc9af1a67dd754af6e",
      "mediaUrl": "https://ipfs.io/ipfs/QmSamy4zqP91X42k6wS7kLJQVzuYJuW2EN94couPaq82A8",
      "mediaHash": "0x21937ba9d821cb0306c7f1a1a2cc5a257509f228ea6abccc9af1a67dd754af6e",
      "mediaType": "image/png",
      "creators": [
        {
          "name": "Story Foundation",
          "address": "0x67ee74EE04A0E6d14Ca6C27428B27F3EFd5CD084",
          "description": "The World's IP Blockchain",
          "contributionPercent": 100,
          "socialMedia": [
            {
              "platform": "Twitter",
              "url": "https://twitter.com/storyprotocol"
            },
            {
              "platform": "Telegram",
              "url": "https://t.me/StoryAnnouncements"
            },
            {
              "platform": "Website",
              "url": "https://story.foundation"
            },
            {
              "platform": "Discord",
              "url": "https://discord.gg/storyprotocol"
            },
            {
              "platform": "YouTube",
              "url": "https://youtube.com/@storyFDN"
            }
          ]
        }
      ],
      "tags": ["Ippy", "Story", "Story Mascot", "Mascot", "Official"], // experimental field
      "ipType": "Character" // experimental field
    }
    ```
  </Tab>

  <Tab title="Music">
    This is an example song generated on [Suno](https://suno.com/) and registered on our testnet. View the below example [on our protocol explorer](https://aeneid.explorer.story.foundation/ipa/0x7d126DB8bdD3bF88d757FC2e99BFE3d77a55509b).

    ```json theme={null}
    {
      "title": "Midnight Marriage",
      "description": "This is a house-style song generated on suno.",
      "createdAt": "1740005219",
      "creators": [
        {
          "name": "Jacob Tucker",
          "address": "0xA2f9Cf1E40D7b03aB81e34BC50f0A8c67B4e9112",
          "contributionPercent": 100
        }
      ],
      "image": "https://cdn2.suno.ai/image_large_8bcba6bc-3f60-4921-b148-f32a59086a4c.jpeg",
      "imageHash": "0xc404730cdcdf7e5e54e8f16bc6687f97c6578a296f4a21b452d8a6ecabd61bcc",
      "mediaUrl": "https://cdn1.suno.ai/dcd3076f-3aa5-400b-ba5d-87d30f27c311.mp3",
      "mediaHash": "0xb52a44f53b2485ba772bd4857a443e1fb942cf5dda73c870e2d2238ecd607aee",
      "mediaType": "audio/mpeg"
    }
    ```
  </Tab>

  <Tab title="AI Agent">
    The main difference here is you should supply `aiMetadata` with a character file. You can provide any character file you want, or use [this ElizaOS example](https://github.com/elizaOS/characterfile/blob/main/examples/example.character.json) as a template.

    View the below example [on our protocol explorer](https://aeneid.explorer.story.foundation/ipa/0x49614De8b2b02C790708243F268Af50979D568d4).

    ```json theme={null}
    {
      "title": "Story AI Agent",
      "description": "This is an example AI Agent registered on Story.",
      "createdAt": "1740005219",
      "creators": [
        {
          "name": "Jacob Tucker",
          "address": "0xA2f9Cf1E40D7b03aB81e34BC50f0A8c67B4e9112",
          "contributionPercent": 100
        }
      ],
      "image": "https://ipfs.io/ipfs/bafybeigi3k77t5h5aefwpzvx3uiomuavdvqwn5rb5uhd7i7xcq466wvute",
      "imageHash": "0x64ccc40de203f218d16bb90878ecca4338e566ab329bf7be906493ce77b1551a",
      "mediaUrl": "https://ipfs.io/ipfs/bafybeigi3k77t5h5aefwpzvx3uiomuavdvqwn5rb5uhd7i7xcq466wvute",
      "mediaHash": "0x64ccc40de203f218d16bb90878ecca4338e566ab329bf7be906493ce77b1551a",
      "mediaType": "image/webp",
      "aiMetadata": {
        "characterFileUrl": "https://ipfs.io/ipfs/bafkreic6eu4hlnwx46soib62rgkhhmlieko67dggu6bzk7bvtfusqsknfu",
        "characterFileHash": "0x5e253875b6d7e7a4e407da899473b168229def8cc6a783957c35996928494d2d"
      }
    }
    ```
  </Tab>
</Tabs>

## Optional Properties

The following properties are optional but can provide additional context about your IP Asset:

<Warning>
  We are still figuring out the best way to define an IPA Metadata Standard. The
  fields below are bound to change or be removed at some point.
</Warning>

| Property Name    | Type               | Description                                                                                                                                                    |
| :--------------- | :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ipType`         | `string`           | Type of the IP Asset, can be defined arbitrarily by the creator. I.e. "character", "chapter", "location", "items", "music", etc                                |
| `relationships`  | `IpRelationship[]` | The detailed relationship info with the IPA's direct parent asset, such as `APPEARS_IN`, `FINETUNED_FROM`, etc. See more examples [here](#relationship-types). |
| `watermarkImage` | `string`           | A separate image with your watermark already applied. This way apps choosing to use it can render this version of the image (with watermark applied).          |
| `media`          | `IpMedia[]`        | An array of supporting media. Media type defined below                                                                                                         |
| `app`            | `StoryApp`         | This is assigned to verified application from Story directly (on a request basis so far). We will map each App ID to a name                                    |
| `tags`           | `string[]`         | Any tags that can help surface this IPA                                                                                                                        |
| `robotTerms`     | `IPRobotTerms`     | Allows you to set Do Not Train for a specific agent                                                                                                            |
| N/A              | N/A                | You can include other values as well.                                                                                                                          |

### Type Definitions

<CodeGroup>
  ```typescript IpRelationship theme={null}
  type IpRelationship = {
    parentIpId: Address;
    type: string; // see "Relationship Types" docs below
  };
  ```

  ```typescript IpMedia theme={null}
  type IpMedia = {
    name: string;
    url: string;
    mimeType: string;
  };
  ```

  ```typescript StoryApp theme={null}
  type StoryApp = {
    id: string;
    name: string;
    website: string;
    action?: string;
  };
  ```

  ```typescript IPRobotTerms theme={null}
  type IPRobotTerms = {
    userAgent: string;
    allow: string;
  };
  ```
</CodeGroup>

### Relationship Types

The different relationship types that can be used for the `relationships` attribute.

#### Story Relationships

1. **APPEARS\_IN** - A character APPEARS\_IN a chapter.

2. **BELONGS\_TO** - A chapter BELONGS\_TO a book.

3. **PART\_OF** - A book is PART\_OF a series.

4. **CONTINUES\_FROM** - A chapter CONTINUES\_FROM the previous one.

5. **LEADS\_TO** - An event LEADS\_TO a consequence.

6. **FORESHADOWS** - An event FORESHADOWS future developments.

7. **CONFLICTS\_WITH** - A character CONFLICTS\_WITH another character.

8. **RESULTS\_IN** - A decision RESULTS\_IN a significant change.

9. **DEPENDS\_ON** - A subplot DEPENDS\_ON the main plot.

10. **SETS\_UP** - A prologue SETS\_UP the story.

11. **FOLLOWS\_FROM** - A chapter FOLLOWS\_FROM the previous one.

12. **REVEALS\_THAT** - A twist REVEALS\_THAT something unexpected occurred.

13. **DEVELOPS\_OVER** - A character DEVELOPS\_OVER the course of the story.

14. **INTRODUCES** - A chapter INTRODUCES a new character or element.

15. **RESOLVES\_IN** - A conflict RESOLVES\_IN a particular outcome.

16. **CONNECTS\_TO** - A theme CONNECTS\_TO the main narrative.

17. **RELATES\_TO** - A subplot RELATES\_TO the central theme.

18. **TRANSITIONS\_FROM** - A scene TRANSITIONS\_FROM one setting to another.

19. **INTERACTED\_WITH** - A character INTERACTED\_WITH another character.

20. **LEADS\_INTO** - An event LEADS\_INTO the climax.?\
    **PARALLEL - story** happening in parallel or around the same timeframe

#### AI Relationships

1. **TRAINED\_ON** - A model is TRAINED\_ON a dataset.

2. **FINETUNED\_FROM** - A model is FINETUNED\_FROM a base model.

3. **GENERATED\_FROM** - An image is GENERATED\_FROM a fine-tuned model.

4. **REQUIRES\_DATA** - A model REQUIRES\_DATA for training.

5. **BASED\_ON** - A remix is BASED\_ON a specific workflow.

6. **INFLUENCES** - Sample data INFLUENCES model output.

7. **CREATES** - A pipeline CREATES a fine-tuned model.

8. **UTILIZES** - A workflow UTILIZES a base model.

9. **DERIVED\_FROM** - A fine-tuned model is DERIVED\_FROM a base model.

10. **PRODUCES** - A model PRODUCES generated images.

11. **MODIFIES** - A remix MODIFIES the base workflow.

12. **REFERENCES** - An AI-generated image REFERENCES original data.

13. **OPTIMIZED\_BY** - A model is OPTIMIZED\_BY specific algorithms.

14. **INHERITS** - A fine-tuned model INHERITS features from the base model.

15. **APPLIES\_TO** - A fine-tuning process APPLIES\_TO a model.

16. **COMBINES** - A remix COMBINES elements from multiple datasets.

17. **GENERATES\_VARIANTS** - A model GENERATES\_VARIANTS of an image.

18. **EXPANDS\_ON** - A fine-tuning process EXPANDS\_ON base capabilities.

19. **CONFIGURES** - A workflow CONFIGURES a model’s parameters.

20. **ADAPTS\_TO** - A fine-tuned model ADAPTS\_TO new data.
