Skip to main content

What is a Notification in Push protocol?

Notifications follow composable blocks that helps achieve modular structure and helps in building on top of them. Any developer can utilize the notification protocol to send out notifications (on-chain or off-chain) to their users from a variety of platforms including web3 protocols, smart contracts, dapps, backend, etc.

These notifications are tied to wallet address of the user and are indexed by push nodes allowing any crypto frontend such as wallet, dapp or mobile app to query and display these notifications for the wallet users along with sending them out as push notifications.

Notification Composable Block

Composability Structure

Each notification is made up of these composable blocks:

Verification - To verify the notification
Identity - To understand the storage format and rules to interpret the notification payload
Payload - To understand what is the type of notification, what data it contains and to whom it should be addresses to
Content - To interpret or extend format types for content inside the notification
  • Verification - It defines the way to verify that the payload is valid by checking sender, source, and authenticitiy of the payload content.
  • Identity - Notification Identity Payload is the standard through which notification payload can be sent to Push Nodes for processing. There are multiple ways by which these payloads can be stored (storage-independent behavior) and identity ensures that the push node are able to understand and construct the notification payload from the data.
  • Payload - Each notification sent to the protocol is essentially a JSON payload which contains data about things a notification contains, notification recipients and even data to encrypt these notifications. This json payload is what makes Push Protocol payload content-independent and allows for expansion to several new types of notifications based on the community needs and as the communication protocol develops further.
  • Content - Notification Content Markdown standardize the content markdown and create a standard for styling and formatting.

Notification Verification Proof

Verification Proof is the outermost composable block that is sent along with the notification to help the network validate the notification sender, the chain from which the notification is sent, and the content of the notification along with any other validation that might be required.

Verification proofs differ based on the platform from which they are sent. For instance, smart contracts verification proof can be validated on-chain and smart contract-based notifications will usually carry transaction hash proofs, while off-chain / gasless notifications usually carry eip712 proofs, though they are capable of carrying smart contract verification proof as well which makes it composable.

Specifications

verificationProofDefinitionProof of verification
eip155:chainId:txHash::uid::optionaluidVerification proof generated from transaction hash of EPNSComm smart contracts on Ethereum or Polygon.The type can be proven by on-chain activity
eip712v1:signature::uid::optionaluidVerification proof generated from off-chain EIP-712 signing of payloadThe type is proven by verifying the signature of eip712.
eip712v2:signature::uid::optionaluidVerification proof generated from off-chain EIP-712 signing of payloadThe type is proven by verifying the signature of eip712
thegraph:graphid+notifcounter::uid::optionaluidVerification proof generated from any subgraphThe type is proven by validating if the subgraph is attached to the channel and then the counter id is used to pick the message and compare the payload with the payload stored on the graph
note

::uid:: is an optional delimiter which if present along with optionaluid allows the proof to be uniquely different.

Understanding Verification Proof

  1. eip155:chainId:txHash::uid::optionaluid - This signifies the on-chain verification. Currently, Ethereum and Polygon are supported networks and it can be verified by resolving the transaction hash from the respective chains and making sure that identity is present in the block.

  2. eip712v1 - This signifies the verification from the off-chain, the verification is done through an EIP-712-based signature.

caution

eip-712v1 has a limitation to support only completed old payloads which include all the parameters of the payload which are part of notification, data, and recipients.

As identity formats like 0, 1 and 3 have single string payload, only identity 2 is compatible with eip-712v1. To overcome this limitation eip-712v2 is introduced which is identity-independent.

  1. eip712v2 - eip712v2:<Proof>, it contains a payload that is future compatible. It means the payload can be dynamic and can be extended for future reference.

  2. thegraph - Notification can be triggered through a subgraph as well They need to call the addSubgraph function from Push Core Contract to add the subgraph. The Push Node will pick up the same and verification proof for this consists of:

    • GraphId: This will be the id of subgraph. It is usually represented as githubid/subgraph name e.g - push/pushsubgraph.
    • notification number[counter] - It will keep the count of Notifications and will process in a successive manner.
    • ::uid::optionaluid - ::uid is an optional delimiter which if present along with optionaluid allows the proof to be uniquely different.

Verification Proof Examples

Transaction Based (eip155:....)

This signifies the verification from the on-chain, currently, Ethereum and Polygon are supported networks and it can be verified by resolving the transaction hash from the respective chains and making sure that identity is present in the block.

1. For Identity 0

{
"verificationProof":"eip155:<chainId>:<TX-Hash>",
"channel": "eip155:42 or 80001:0xd8634c39bbfd4033c0d3289c4515275102423681",
"recipient": "eip155:42 or 80001:0xd8634c39bbfd4033c0d3289c4515275102423681",
"source": "ETH_TEST_SEPOLIA or POLYGON_TEST_MUMBAI or ETH_MAINNET"
"identity": "0+<Notification-Type>+<Title>+<body>"
}

2. For Identity 1

{
"verificationProof":"eip155:<chainId>:<TX-Hash>",
"channel": "eip155:42 or 80001:0xd8634c39bbfd4033c0d3289c4515275102423681",
"recipient": "eip155:42 or 80001:0xd8634c39bbfd4033c0d3289c4515275102423681",
"source": "ETH_TEST_SEPOLIA or POLYGON_TEST_MUMBAI or ETH_MAINNET"
"identity": "1+<IPFS-HASH>"
}

3. For Identity 2

{
"verificationProof": "eip155:<chainId>:<TX-Hash>",
"channel": "eip155:42 or 80001:0xD8634C39BBFd4033c0d3289C4515275102423681",
"recipient": "eip155:42 or 80001:0xD8634C39BBFd4033c0d3289C4515275102423681",
"source": "ETH_TEST_SEPOLIA or POLYGON_TEST_MUMBAI or ETH_MAINNET",
"identity": "2+<Payload-in-form-of-string>"
}

3. For Identity 3

{
"verificationProof": "eip155:<chainId>:<TX-Hash>",
"channel": "eip155:42 or 80001:0xd8634c39bbfd4033c0d3289c4515275102423681",
"recipient": "eip155:42 or 80001:0xd8634c39bbfd4033c0d3289c4515275102423681",
"source": "THE_GRAPH",
"identity": "3+graph:<subgraph-id>+<notification number>"
}
EIP-712v1

This signifies the verification from the off-chain, the verification is done through an EIP-712-based signature.

caution

EIP-712v1 - It contains a fully loaded old payload. This is deprecated but present to provide backward compatibility.

This has a limitation to support only the completed old payload which includes all the parameters of the payload which are part of notification, data, and recipients. As identity formats like 0, 1 and 3 have single string payload, only identity 2 is compatible with eip-712v1. To overcome this limitation eip-712v2 is identity independent.

{
"channel": "0x69e666767Ba3a661369e1e2F572EdE7ADC926029",
"recipient": "0x69e666767Ba3a661369e1e2F572EdE7ADC926029",
"signature": "<Signature generated using eip712>",
"deployedContract": "0x99047d328496C14016222a998564B334A4A5723f",
"chainId": "42",
"payload": {
"data": {
"acta": "",
"aimg": "",
"amsg": "Current BTC price is - 47,785.10USD",
"asub": "",
"type": "1",
"secret": ""
}
},
"type": "1",
"op": "write"
}
EIP-712v2 - eip712v2:<Proof>

Contains a payload that is future compatible. It means the payload can be dynamic and can be extended for future reference.

{
"verificationProof": "eip712v2:<Proof>",
"channel": "eip155:42 or 80001:0xd8634c39bbfd4033c0d3289c4515275102423681",
"recipient": "eip155:42 or 80001:0xd8634c39bbfd4033c0d3289c4515275102423681",
"source": "ETH_TEST_SEPOLIA or POLYGON_TEST_MUMBAI or ETH_MAINNET",
"identity": "0+1+Test Title+Test Body"
}
{
"verificationProof": "eip712v2:<Proof>",
"channel": "eip155:42 or 80001:0xd8634c39bbfd4033c0d3289c4515275102423681",
"recipient": "eip155:42 or 80001:0xd8634c39bbfd4033c0d3289c4515275102423681",
"source": "ETH_TEST_SEPOLIA or POLYGON_TEST_MUMBAI or ETH_MAINNET",
"identity": "1+bafkreicuttr5gpbyzyn6cyapxctlr7dk2g6fnydqxy6lps424mcjcn73we"
}
{
"verificationProof": "eip712v2:<Proof>",
"channel": "eip155:42 or 80001:0xd8634c39bbfd4033c0d3289c4515275102423681",
"recipient": "eip155:42 or 80001:0xd8634c39bbfd4033c0d3289c4515275102423681",
"source": "THE_GRAPH",
"identity": "3+graph:<subgraph-id>+<notification number>"
}
{
"verificationProof": "eip712v1:<Proof>",
"channel": "eip155:42 or 80001:0xD8634C39BBFd4033c0d3289C4515275102423681",
"recipient": "eip155:42 or 80001:0xD8634C39BBFd4033c0d3289C4515275102423681",
"source": "ETH_TEST_SEPOLIA or POLYGON_TEST_MUMBAI or ETH_MAINNET",
"identity": "2+{\\'notification\\':{\\'title\\':\\'TEST Title\\',\\'body\\':\\'Test Body\\'},\\'data\\':{\\'acta\\':\\'\\',\\'aimg\\':\\'\\',\\'amsg\\':\\'Test Message\\',\\'asub\\':\\'\\',\\'type\\':\\'3\\',\\'etime\\':\\'\\',\\'hidden\\':\\'\\'}}"
}
TheGraph
{
"verificationProof": `graph:<subgraph-id>+<notification number>`,
"channel": "eip155:42 or 80001:0xD8634C39BBFd4033c0d3289C4515275102423681",
"recipient": "eip155:42 or 80001:0xD8634C39BBFd4033c0d3289C4515275102423681",
"source": "THE_GRAPH",
"identity": `3+graph:<subgraph-id>+<notification number>`
}

Notification Identity

Identity defines where the notification is coming from and the rules by which we can get the payload JSON of that specific notification. Currently, supported identities are Minimal, IPFS, Direct, and Subgraph.

Specifications

Each notification identity carries at least two parameters which are joined by + delimiter.

  • Storage Type: The first parameter represents the identity type used (Minimal, IPFS, Direct, etc). The type id represents where the payload is stored or coming from.
  • Payload storage info: Hash of the payload representing proof or pointer from which the payload can be retrieved. The second parameter represents either the hash or identifying information that can be used to fetch the necessary JSON which can also be made of composable information.

Storage Types As of now, there are 4 types of storage that are supported:

IdTypeDefintion
0MinimalRecommended for Smart Contract
1IPFSIndicates storage on IPFS
2Direct PayloadIndicates storage of direct payload
3SubGraphIndicates storage on the subgraph

Identity Examples

Identity Type 0

Format: 0+<Notification Payload Type>+<Title>+<Body>

<Notification Payload Type>: Type of notification (Broadcast, Subset, Targeted, Secret, etc)

<Title>: This will be the title of the Message.

<Body>: This will be the body/description of the Message.

Example:

0+1+Hello+This is a broadacasted notification
Identity Type 1

Format: 1+<IPFS HASH (cid)>

<IPFS HASH (cid)>: The IPFS hash pointing to the payload. The payload should be as per Push protocol standard for Notification.

Example:

1+b45165ed3cd437b9ffad02a2aad22a4ddc69162470e2622982889ce5826f6e3d
Identity Type 2

Format: 2+<Payload in string format>

<Payload in string format>: The payload as per Push standard should be stringified and attested to the storage type.

Example:

2+{\\"notification\\":{\\"title\\":\\"TEST Title\\",\\"body\\":\\"Test Body\\"},\\"data\\":{\\"acta\\":\\"\\",\\"aimg\\":\\"\\",\\"amsg\\":\\"Test Message\\",\\"asub\\":\\"\\",\\"type\\":\\"3\\",\\"etime\\":\\"\\",\\"hidden\\":\\"\\"}}
Identity Type 3

Format: 3+<subgraphId>+<notification number[counter]>

<subgraphId>: The subgraph id deployed in The Graph. It should be in the format of <github id>/<subgraph name>. notification number[counter]: Every subgraph notification has a notification number attached. You will need to pass the subgraph number to identify which subgraph data should be sent as a notification.

Notification Payload

Each notification sent to the protocol is essentially a JSON payload, bytes data, or hash/pointer of the JSON payload.

The protocol distinguishes payloads content which will contain the content which needs to be displayed, rules to display/morph the content, the recipients to which the content is meant to be delivered along with the encryption method used if the content is encrypted.

The notification payload type for Push is infinitely extensible and opens a huge range of possibilities including multi-factor authentication, payments, blacklisting address (Multi-sig contract as a channel with exchanges as their subscribers), etc.

The data defined in the JSON payload they carry is used to interpret and extend that functionality.

Specifications

{
"notification": {
"title": "The title of your message displayed on the screen (50 Chars)",
"body": "The intended message displayed on the screen (180 Chars)"
},
"data": {
"type": "1" or "3" or "4", // 1 is broadcast, 3 is targeted, 4 is subset
"sectype": null or [Encryption_Method], // for example: aes+eip85
"asub": "encrypted by secret using sectype | [Optional] The subject of the message displayed inside app (80 Chars)",
"amsg": "encrypted by secret using sectype | [Optional] The intended message displayed inside app (500 Chars)",
"acta": "encrypted by secret using sectype | [Optional] The cta link parsed inside the app",
"aimg": "encrypted by secret using sectype | [Optional] The image url which is shown inside the app",
"etime": "[Optional] if given, notif will be deleted after this in epoch",
"hidden" :"[Optional] if given, notif will not show in user feed"
},
"recipients": 0x0 for type 1, 0xtarget for type 3, array for type 4 [
0x1: null or [{
secret: [secret used to encrypt]
}],
0x2: null or [{
secret: [secret used to encrypt]
}],
...
0xn: null or [{
secret: [secret used to encrypt]
}]
}
Payload variableDescription
notification (Required)Represents the notification typically delivered on the home screen of the platform (mobile, tablet, web, extension, etc), the icon of the channel is automatically added to outline where the notification is coming from.
title (Required)The title of the message displayed on the screen differs from the data JSON because the title while transforming the payload can be different from the title presented. For example, secret notification title are always transformed to say Channel has sent you a secret notification.
body (Required)The body of the message displayed on the screen differs from the data JSON because the title while transforming the payload can be different from the title presented. For example, secret notification body are always transformed to say Please open the dApp / app to view your notification.
data (Optional)The data field present here forms the visual feedBox for the user. Indicates the data field the payload will carry. This allows the notification to transform according to the payload type and the content defined on the platform frontend (ie: app, dApp, wallet, etc).
type (Required)Each payload has a type that tells how the data should be interpreted, this type is mirrored on the protocol function call as well.
sectype (Required)is the encryption technique used for the secret/encrypted notification. In open notifs it can be entered null.
asub (Optional)is the subject shown in the feed item.
amsg (Optional)is the message shown in the feed item, has rich text formatting.
acta (Optional)is the call to action of that feed item.
aimg (Optional)is the image shown in the feed item, this field is also capable of carrying youtube links.
etime (Optional)if given, notif will be deleted after this in epoch
recipients (Required)Recipients address needs to be defined depending on the payload type, if 0x00 is provided it will represents all the subscribers of the channel and in the case of secret payload each subscriber address will be mapped with the secret.
secret (Optional)is required for encryption and decryption of payload data, this will be mapped with the user address as key-value pair.

Payload Examples

Standard Payload Structure
{
"notification": {
"title": "The title of your message displayed on screen (50 Chars)",
"body": "The intended message displayed on screen (180 Chars)"
},
"data": {
"type": "1" or "3" or "4", // 1 is broadcast, 3 is targeted, 4 is subset
"sectype": null or [Encryption_Method] // for example: aes+eip85
"asub": "encrypted by secret using sectype | [Optional] The subject of the message displayed inside app (80 Chars)",
"amsg": "encrypted by secret using sectype | [Optional] The intended message displayed inside app (500 Chars)",
"acta": "encrypted by secret using sectype | [Optional] The cta link parsed inside the app",
"aimg": "encrypted by secret using sectype | [Optional] The image url which is shown inside the app",
"etime": "[Optional] if given, notif will be deleted after this in epoch"
"hidden" :"[Optional] if given, notif will not show in user feed"
},
"recipients": 0x0 for type 1, 0xtarget for type 3 or [
0x1: null or [{
secret: [secret used to encrypt]
}],
0x2: null or [{
secret: [secret used to encrypt]
}],
...
0xn: null or [{
secret: [secret used to encrypt]
}] for type 4
}
Broadcast Payload
{
"notification": {
"title": "The title of your message displayed on screen (50 Chars)",
"body": "The intended message displayed on screen (180 Chars)"
},
"data": {
"type": "1"
"sectype": null
"asub": "[Optional] The subject of the message displayed inside app (80 Chars)",
"amsg": "[Optional] The intended message displayed inside app (500 Chars)",
"acta": "[Optional] The cta link parsed inside the app",
"aimg": "[Optional] The image url which is shown inside the app",
"etime": "[Optional] if given, notif will be deleted after this in epoch"
"hidden" :"[Optional] if given, notif will not show in user feed"
},
"recipients": 0x0
}
Targeted Payload
{
"notification": {
"title": "The title of your message displayed on screen (50 Chars)",
"body": "The intended message displayed on screen (180 Chars)"
},
"data": {
"type": "3"
"sectype": null
"asub": "[Optional] The subject of the message displayed inside app (80 Chars)",
"amsg": "[Optional] The intended message displayed inside app (500 Chars)",
"acta": "[Optional] The cta link parsed inside the app",
"aimg": "[Optional] The image url which is shown inside the app",
"etime": "[Optional] if given, notif will be deleted after this in epoch"
"hidden" :"[Optional] if given, notif will not show in user feed"
},
"recipients": 0xtarget
}
Subset Payload
{
"notification": {
"title": "The title of your message displayed on screen (50 Chars)",
"body": "The intended message displayed on screen (180 Chars)"
},
"data": {
"type": "4"
"sectype": null
"asub": "[Optional] The subject of the message displayed inside app (80 Chars)",
"amsg": "[Optional] The intended message displayed inside app (500 Chars)",
"acta": "[Optional] The cta link parsed inside the app",
"aimg": "[Optional] The image url which is shown inside the app",
"etime": "[Optional] if given, notif will be deleted after this in epoch"
"hidden" :"[Optional] if given, notif will not show in user feed"
},
"recipients": [
0x1: null,
0x2: null,
...
0xn: null
]
}
Encrypted Payload
{
"notification": {
"title": "The title of your message displayed on screen (50 Chars)",
"body": "The intended message displayed on screen (180 Chars)"
},
"data": {
"type": "4"
"sectype": "aes+eip85"
"asub": "encrypted by secret using sectype | [Optional] The subject of the message displayed inside app (80 Chars)",
"amsg": "encrypted by secret using sectype | [Optional] The intended message displayed inside app (500 Chars)",
"acta": "encrypted by secret using sectype | [Optional] The cta link parsed inside the app",
"aimg": "encrypted by secret using sectype | [Optional] The image url which is shown inside the app",
"etime": "[Optional] if given, notif will be deleted after this in epoch"
"hidden" :"[Optional] if given, notif will not show in user feed"
},
"recipients": [
0x1:[{
secret: [secret used to encrypt]
}],
0x2: [{
secret: [secret used to encrypt]
}],
...
0xn: [{
secret: [secret used to encrypt]
}]
]
}

Notification Content

Notification Feeds have the ability to display customized content. By adopting and standardizing the notification content markdown, it ensures that we can keep on advancing the ways notification are presented on the frontend / UI.

Specifications

Markdown FormatUse CaseStyling effects
**Bold**For EmphasisFor Bold
*Italic*For EmphasisFor Italics
***Bold&Italics***For EmphasisFor Bold and Italics
\nFor SegregationFor new line
<span color="white">Hello World</span>For colored textFor white color
<span color="#ANYHEXCODE"> Hello world </span>For colored textSupports any color hexcode
<span color="primary">Hello World </span>For colored textPush Primary colored Text
<span color="secondary">Hello World </span>For colored textPush Secondary colored Text
<span color="tertiary">Hello World </span>For colored textPush Tertiary colored Text
[PUSH website](https://push.org)For URL'sUnderlined, Red Colored Text
[timestamp: 1699032018]For Timestampconverts Epoch timestamps to human readable timestamp

Push Notification markdown live playground

// DO NOT FORGET TO IMPORT LIBRARIES// NOT NEEDED HERE SINCE PLAYGROUND IMPORTS INTERNALLY
// import { NotificationItem } from @pushprotocol/restapi;
function App(props) {
  return (
    <>
      <h2>Markdown Notification to style your notification as per your need</h2>
          <NotificationItem
           notificationTitle={"Title"}
           notificationBody={"***Bold&Italic*** \n **Bold** \n *Italic* \n <span color='green'>green text</span> \n [PUSH website](https://push.org) \n [timestamp: 1699347011]"}
           image={"https://push.org/assets/pushIcon.svg"}
           chainName={"ETH_TEST_SEPOLIA"}
           icon={"https://push.org/assets/pushIcon.svg"}
           app={"PUSH"}
          />
    </>
  );
}
LIVE PREVIEW

Content Examples

For Timestamp

> Markdown - [ts: 1699032018]
> Example - Friday, November 3, 2023 5:20:18 PM

For Bold

> Markdown - **Bold**
> Example - **PUSH IMPROVEMENT PROPOSAL**

For Italics

> Markdown - *Italics*
> Example - *Slant text*

For Bold and Italics

> Markdown - ***Bold&Italics***
> Example - ***Push guidelines***

For new Line

> Markdown - \n
> Example - Sub category of Notification PRC - \n
* Content

For white color

> Markdown - <PUSHText color="white">PUSH</PUSHText>
> Example - <PUSHText color="white">w2w chat</PUSHText>

For any color in hexcode

> Markdown - <PUSHText color=”#ANYHEXCODE”> Hello world </PUSHText>
> Example - <PUSHText color=”#00FF00”> Push Nodes </PUSHText>

For Push primary color

> Markdown - <PUSHText color="primary">Hello World </PUSHText>
> Example - <PUSHText color="primary"> Analytics dashboard </PUSHText>

For Push secondary color

> Markdown - <PUSHText color="secondary">Hello World </PUSHText>
> Example - <PUSHText color="secondary">EPNS Dapp </PUSHText>

For Push tetiary color

> Markdown - <PUSHText color="tertiary">Hello World </PUSHText>
> Example - <PUSHText color="tertiary">EPNS Browser extension</PUSHText>

For Underlined, Red Colored

> Markdown - <EPNSLink color=”red”>[EPNS Website](https://www.epns.io) </EPNSLink>
> Example - <PUSHText color="green" link="https://www.google.com">Hello World </PUSHText>