Making Decentrialized Social Easy

Getting started building on Decentralized Social is as easy as deploying a Web2 API.

Build What You Want

Gateway offers a suite of tools you can pick and choose from to build the best applications for your users.

  • Add decentralized authentication and onboarding workflows
  • Connect your users with their universal social graph
  • Read, write, and interact with social media content
  • More coming...

Web2 API Simplicity with Decentralized Power

  • Build your applications faster
  • Own your infrastructure
  • OpenAPI/Swagger out of the box
  • Optimized Docker images

Basic Architecture

Gateway provides a simple API to interact with the Frequency social layers of identity, graph, content, and more.

These microservices are completely independent of one another, so you can use only those pieces you want or need.

{{#svg-embed ./src/TopLevel.svg Gateway Application Microservice Diagram}}

Key Microservices

Account Service

The Account Service enables easy interaction with accounts on Frequency. Accounts are defined as an msaId (64-bit identifier) and can contain additional information such as a handle, keys, and more.

  • Account authentication and creation using SIWF
  • Delegation management
  • User Handle creation and retrieval
  • User key retrieval and management

Graph Service

The Graph Service enables easy interaction with social graphs on Frequency. Each Graph connection on Frequency can be private or public and can be unidirectional (a follow) or bidiectional (double opt-in friend connection).

  • Fetch user graph
  • Update delegated user graphs
  • Watch graphs for external updates

Content Publishing Service

The Content Publishing Service enables the creation of new content-related activity on Frequency.

  • Create posts to publicly broadcast
  • Create replies to posts
  • Create reactions to posts
  • Create updates to existing content
  • Request deletion of content
  • Store and attach media with IPFS

Content Watcher Service

The Content Watcher Service enables client applications to process content found on Frequency by registering for webhook notifications, triggered when relevant content is found, eleminating the need to interact with the chain for new content.

  • Parses and validates Frequency content
  • Filterable webhooks
  • Scanning control

Get Started

Getting Started

In this tutorial, you will setup the Social App Template Example Application that uses Gateway Services. These will all run locally and connect to the public Frequency Testnet. This will give you a quick introduction to a working integration with Gateway Services and a starting place to explore the possibilities.

Expected Time: ~5 minutes

Step 1: Prerequisites

Before you begin, ensure you have the following installed on your machine:

Step 2: Register on Testnet

To have your application interact on Frequency Testnet, you will need to register as a Provider. This will enable users to delegate to you, and your chain actions to be free via Capacity.

Create an Application Account in a Wallet

  • Open a wallet extension such as the Polkadot extension
  • Follow account creation steps
  • Make sure to keep the seed phrase for the service configuration step

Detailed Instructions

Acquire Testnet Tokens

Visit the Frequency Testnet Faucet and get tokens: Testnet Faucet

Create a Provider

Creating your provider account is easy via the Provider Dashboard.

  • Use the same browser with the wallet extension
  • Visit the Provider Dashboard
  • Select Become a Provider
  • Select the Testnet Paseo network
  • Connect the Application Account created earlier
  • Select Create an MSA and approve the transaction popups
  • Choose a public Provider name (e.g. "Cool Test App") and continue via Create Provider
  • Stake for Capacity by selecting Stake to Provider and stake 100 XRQCY Tokens

Provider Dashboard Example

Step 3: Configure and Run the Example

Clone the Example Repository

git clone https://github.com/ProjectLibertyLabs/social-app-template.git
cd social-app-template

Run the Configuration Script

./start.sh

Testnet Setup Help

Use default values when uncertain.

  • Do you want to start on Frequency Paseo Testnet? Yes!
  • Enter Provider ID This is Provider Id from the Provider Dashboard
  • Enter Provider Seed Phrase This is the seed phrase saved from the wallet setup
  • Do you want to change the IPFS settings?

Step 4: Done & What Happened?

You should now be able to access the Social App Template at http://localhost:3000!

SAT Screenshot

What happened in the background?

All the different services needed were started in Docker (Docker Desktop Screenshot): Docker Desktop Screenshot

Step 5: Shutdown

Stop all the Docker services via the script (with the option to remove saved data), or just use Docker Desktop.

./stop.sh

What's Next?

Core Concepts

Global State

Frequency provides a shared global state to make interoperability and user control fundamental to the internet. Applications provide unique experiences to their users while accessing the content and graph connections from other applications. Your application can then interact with this shared global state seamlessly, in the same way that modern networking software allows isolated computers to interact seamlessly over a global network moving past the artificial application boundaries.

User Control with Delegation

Users are at the core of every application and network. While users must maintain ultimate control, delegation to your application gives you the ability to provide seamless experiences for your users and their data.

Learn more about Delegation in Frequency Documentation.

Interoperability Between Apps

Frequency enables seamless interaction and data sharing between different applications built on its platform. This interoperability is facilitated by:

  • Standardized Protocols: Frequency uses the Decentralized Social Networking Protocol (DSNP), an open Web3 protocol that ensures compatibility between different applications.
  • Common Data Structures: By using standardized data structures for user profiles, messages, and other social interactions, Frequency ensures that data can be easily shared and interpreted across different applications.
  • User Control: Users can switch between different applications without losing their social connections or content, ensuring continuity and control over their digital presence.

By leveraging these principles and infrastructures, Frequency provides a robust platform for developing decentralized social applications that are secure, scalable, and user-centric.

Learn More

Blockchain Basics

Overview of Blockchain Principles for Social Applications

Blockchain technology is a decentralized ledger system where data is stored across multiple nodes, ensuring transparency, security, and immutability.

Reading the Blockchain

RPCs, Universal State, Finalized vs Non-Finalized

  • RPCs (Remote Procedure Calls): RPCs are used to interact with the blockchain network. They allow users to query the blockchain state, submit transactions, and perform other operations by sending requests to nodes in the network.

  • Universal State: The blockchain maintains a universal state that is agreed upon by all participating nodes. This state includes all the data and transactions that have been validated and confirmed.

  • Finalized vs Non-Finalized:

    • Finalized Transactions: Once a transaction is confirmed and included in a block, it is considered finalized. Finalized transactions are immutable and cannot be changed or reverted.
    • Non-Finalized Transactions: Transactions that have been submitted to the network but are not yet included in a block are considered non-finalized. They are pending confirmation and can still be altered or rejected.

Writing Changes to the Blockchain

Transactions

  • Transactions are the primary means of updating the blockchain state. They can involve transferring tokens, or executing other predefined operations.

Nonces

  • Each transaction includes a nonce, a unique number that prevents replay attacks. The nonce ensures that each transaction is processed only once and in the correct order.

Finalization

  • Finalization is the process of confirming and adding a transaction to a block. Once a transaction is included in a block and the block is finalized, the transaction becomes immutable.

Block Time

  • Block time refers to the interval at which new blocks are added to the blockchain. It determines the speed at which transactions are confirmed and finalized. Shorter block times lead to faster transaction confirmations but can increase the risk of network instability.

Why Blockchain

  • Decentralization: Eliminates the need for a central authority, ensuring that users have control over their data and interactions.
  • Transparency: All transactions are recorded on a public ledger, providing visibility into the operations of social platforms.
  • Security: Advanced cryptographic methods secure user data and interactions, making it difficult for malicious actors to tamper with information.
  • Immutability: Once data is recorded on the blockchain, it cannot be altered, ensuring the integrity of user posts, messages, and other social interactions.
  • User Empowerment: Users can own their data and have the ability to move freely between different platforms without losing their social connections or content.

Interoperability Between Frequency Social Apps

Frequency enables seamless interaction and data sharing between different social dapps built on its platform. This interoperability is facilitated by:

  • Standardized Protocols: Frequency uses the Decentralized Social Networking Protocol (DSNP), an open Web3 protocol that ensures compatibility between different social dapps.
  • Common Data Structures: By using standardized data structures for user profiles, messages, and other social interactions, Frequency ensures that data can be easily shared and interpreted across different applications.
  • Interoperable APIs: Frequency provides a set of REST APIs that allow developers to build applications capable of interacting with each other, ensuring a cohesive user experience across the ecosystem.
  • User Control: Users can switch between different social dapps without losing their social connections or content, ensuring continuity and control over their digital presence.

By leveraging these principles and infrastructures, Frequency provides a robust platform for developing decentralized social applications that are secure, scalable, and user-centric.

Frequency Networks

Mainnet

The Frequency Mainnet is the primary, production-level network where real transactions and interactions occur. It is fully secure and operational, designed to support live applications and services. Users and developers interact with the Mainnet for all production activities, ensuring that all data and transactions are immutable and transparent.

Key Features:

  • High Security: Enhanced security protocols to protect user data and transactions.
  • Immutability: Once data is written to the Mainnet, it cannot be altered.
  • Decentralization: Fully decentralized network ensuring no single point of control.
  • Real Transactions: All transactions on the Mainnet are real and involve actual tokens.

URLs

Testnet

The Frequency Testnet is a testing environment that mirrors the Mainnet. It allows developers to test their applications and services in a safe environment without risking real tokens. The Testnet is crucial for identifying and fixing issues before deploying to the Mainnet.

Key Features:

  • Safe Testing: Enables developers to test applications without real-world consequences.
  • Simulated Environment: Mirrors the Mainnet to provide realistic testing conditions.
  • No Real Tokens: Uses test tokens instead of real tokens, eliminating financial risk.
  • Frequent Updates: Regularly updated to incorporate the latest features and fixes for testing purposes.

URLs

Local

The Local network setup is a private, local instance of the Frequency blockchain that developers can run on their own machines. It is used for development, debugging, and testing in a controlled environment. The Local network setup provides the flexibility to experiment with new features and configurations without affecting the Testnet or Mainnet.

Key Features:

  • Local Development: Allows developers to work offline and test changes quickly.
  • Customizable: Developers can configure the Local network to suit their specific needs.
  • Isolation: Isolated from the Mainnet and Testnet, ensuring that testing does not interfere with live networks.
  • Rapid Iteration: Facilitates rapid development and iteration, allowing for quick testing and debugging.

URLs

Using Polkadot.js Explorer

To interact with the Frequency networks using the Polkadot.js Explorer, follow these steps:

  1. Open Polkadot.js Explorer:

  2. Select Frequency Network:

    • Click on the network selection dropdown at the top left corner of the page.
    • Choose "POLKADOT & PARACHAINS -> Frequency Polkadot Parachain" for the main network.
    • Choose "TEST PASEO & PARACHAINS -> Frequency Paseo Parachain" for the test network.
    • For local development, connect to your local node by selecting "DEVELOPMENT -> Local Node or Custom Endpoint" and entering the URL of your local node (e.g., http://localhost:9933).
  3. Connect Your Wallet:

    • Ensure your Polkadot-supported wallet is connected.
    • You will be able to see and interact with your accounts and transactions on the selected Frequency network.

By using these steps, you can easily switch between the different Frequency networks and manage your blockchain activities efficiently.

Gateway Architecture

Authentication

Gateway and Frequency provide authentication, but not session management. Using cryptographic signatures, you will get proof the user is authenticated without passwords or other complex identity systems to implement. Your application still must manage sessions as is best for your custom needs.

What does it mean for Applications?

  • Web2 APIs: Typically use OAuth, API keys, or session tokens for authentication.
  • Frequency APIs: Utilize cryptographic signatures for secure authentication, ensuring user identity and data integrity.

SIWF/SIWA

Sign In With Frequency (SIWF) and Sign In With Access (SIWA) are methods for authenticating users in the Frequency ecosystem. SIWF allows users to authenticate using their Frequency accounts, providing a secure and decentralized way to manage identities.

  • SIWF Implementation: Users sign in using their Web3 wallets, which generate cryptographic signatures for authentication. This process eliminates the need for traditional usernames and passwords, enhancing security and user privacy.

Account Service

The Account Service in Gateway handles user account management, including creating accounts, managing keys, and delegating permissions. This service replaces traditional user models with decentralized identities and provides a robust framework for user authentication and authorization.

Data Storage

What does it mean for Frequency?

  • Web2 APIs: Data is stored in centralized databases managed by the service provider.
  • Frequency APIs: Data is stored on the decentralized blockchain (metadata) and off-chain storage (payload), ensuring transparency and user control.

IPFS

InterPlanetary File System (IPFS) is a decentralized storage solution used in the Frequency ecosystem to store large data payloads off-chain. IPFS provides a scalable and resilient way to manage data, ensuring that it is accessible and verifiable across the network.

  • Usage in Gateway: Content Publishing Service uses IPFS to store user-generated content such as images, videos, and documents. The metadata associated with this content is stored on the blockchain, while the actual files are stored on IPFS, ensuring decentralization and availability.

Blockchain

The Frequency blockchain stores metadata and transaction records, providing a secure and user-controlled data store. This ensures that all interactions are transparent and traceable, enhancing trust in the system.

  • Usage in Gateway: Metadata for user actions, such as content publication, follows/unfollows, and other social interactions, are stored on the blockchain. This ensures that all actions are verifiable and under user control.

Local/Application Data

For efficiency and performance, certain data may be stored locally or within application-specific storage systems. This allows for quick access and manipulation of frequently used data while ensuring that critical information remains secure on the blockchain.

Application / Middleware

Hooking Up All the Microservices

Gateway is designed to support a modular and microservices-based approach. Each service (e.g., Account Service, Graph Service, Content Publishing Service) operates independently but can interact through well-defined APIs.

Here is Where Your Custom Code Goes!

Developers can integrate their custom code within this modular framework, extending the functionality of the existing services or creating new services that interact with the Frequency ecosystem.

Standard Services Gateway Uses

Redis

Redis is a key-value store used for caching and fast data retrieval. It is often employed in microservices architectures to manage state and session data efficiently.

  • Why Redis: Redis provides low-latency access to frequently used data, making it ideal for applications that require real-time performance.
  • Usage in Gateway: Redis can be used to cache frequently accessed data, manage session states, and optimize database queries.

BullMQ

BullMQ is a Node.js library for creating robust job queues with Redis.

  • Struture for Redis Queues: BullMQ enhances Redis by providing a reliable and scalable way to manage background jobs and task queues, ensuring that tasks are processed efficiently and reliably.
  • Usage in Gateway: BullMQ can be used to handle background processing tasks such as sending notifications, processing user actions, and managing content updates.

IPFS Kubo API

Kubo is an IPFS implementation and standard API designed for high performance and scalability.

  • Usage in Gateway: Kubo IPFS is used to manage the storage and retrieval of large files in the Frequency ecosystem, ensuring that data is decentralized and accessible.

Migrating from Web2 to Web3

Step-by-Step Migration Guide

  1. Assess Your Current Web2 Application

    • Identify core functionalities.
    • Analyze data structures.
    • Review user authentication.
  2. Understand Frequency and Gateway Services

    • Learn about Frequency blockchain architecture.
    • Understand Gateway services (Account, Graph, Content Publishing, Content Watcher).
  3. Set Up Your Development Environment

    • Install Docker, Node.js, and a Web3 wallet.
    • Clone the Gateway service repositories.
    • Set up Docker containers.
  4. Configure Gateway Services

    • Create and configure .env files with necessary environment variables.
  5. Migrate User Authentication

    • Integrate Web3 authentication using MetaMask or another Web3 wallet.
    • Configure MetaMask to connect to the Frequency TestNet.
  6. Migrate Data Storage

    • Transition to decentralized storage.
    • Use Frequency blockchain for metadata and off-chain storage for payload data.
  7. Migrate Core Functionalities

    • Use the Content Publishing Service for creating feeds and posting content.
    • Use the Graph Service for managing social connections.
    • Use the Content Watcher Service for retrieving the latest state of feeds and reactions.
  8. Test and Validate

    • Perform functional, performance, and security testing.
  9. Optimize and Deploy

    • Optimize your application for performance on the Frequency blockchain.
    • Deploy your migrated application to the production environment.
  10. Educate Your Users

    • Provide documentation and support for user onboarding.
    • Establish a feedback loop to gather user feedback and make improvements.

By following these steps, you can successfully migrate your Web2 application to the Gateway and Frequency Web3 environment.

Services

Account Service

The Account Service enables easy interaction with accounts on Frequency. Accounts are defined as an msaId (64-bit identifier) and can contain additional information such as a handle, keys, and more.

  • Account authentication and creation using SIWF
  • Delegation management
  • User Handle creation and retrieval
  • User key retrieval and management

See Account Service Details & API Reference

Graph Service

The Graph Service enables easy interaction with social graphs on Frequency. Each Graph connection on Frequency can be private or public and can be unidirectional (a follow) or bidiectional (double opt-in friend connection).

  • Fetch user graph
  • Update delegated user graphs
  • Watch graphs for external updates

See Graph Service Details & API Reference

Content Publishing Service

The Content Publishing Service enables the creation of new content-related activity on Frequency.

  • Create posts to publicly broadcast
  • Create replies to posts
  • Create reactions to posts
  • Create updates to existing content
  • Request deletion of content
  • Store and attach media with IPFS

See Content Publishing Service Details & API Reference

Content Watcher Service

The Content Watcher Service enables client applications to process content found on Frequency by registering for webhook notifications, triggered when relevant content is found, eleminating the need to interact with the chain for new content.

  • Parses and validates Frequency content
  • Filterable webhooks
  • Scanning control

See Content Watcher Service Details & API Reference

Account Service

The Account Service provides functionalities related to user accounts on the Frequency network. It includes endpoints for managing user authentication, account details, delegation, keys, and handles.

API Reference

Open Direct API Reference Page

Path Table

MethodPathDescription
GET/v1/accounts/siwfGet the Sign In With Frequency configuration
POST/v1/accounts/siwfRequest to Sign In With Frequency
GET/v1/accounts/{msaId}Fetch an account given an MSA Id
GET/v1/accounts/account/{accountId}Fetch an account given an Account Id
GET/v1/accounts/retireMsa/{accountId}Get a retireMsa unsigned, encoded extrinsic payload.
POST/v1/accounts/retireMsaRequest to retire an MSA ID.
GET/v2/delegations/{msaId}Get all delegation information associated with an MSA Id
GET/v2/delegations/{msaId}/{providerId}Get an MSA's delegation information for a specific provider
GET/v1/delegation/{msaId}Get the delegation information associated with an MSA Id
GET/v1/delegation/revokeDelegation/{accountId}/{providerId}Get a properly encoded RevokeDelegationPayload that can be signed
POST/v1/delegation/revokeDelegationRequest to revoke a delegation
POST/v1/handlesRequest to create a new handle for an account
POST/v1/handles/changeRequest to change a handle
GET/v1/handles/change/{newHandle}Get a properly encoded ClaimHandlePayload that can be signed.
GET/v1/handles/{msaId}Fetch a handle given an MSA Id
POST/v1/keys/addAdd new control keys for an MSA Id
GET/v1/keys/{msaId}Fetch public keys given an MSA Id
GET/v1/keys/publicKeyAgreements/getAddKeyPayloadGet a properly encoded StatefulStorageItemizedSignaturePayloadV2 that can be signed.
POST/v1/keys/publicKeyAgreementsRequest to add a new public Key
GET/healthzCheck the health status of the service
GET/livezCheck the live status of the service
GET/readyzCheck the ready status of the service

Reference Table

NamePathDescription
WalletLoginConfigResponseDto#/components/schemas/WalletLoginConfigResponseDto
HandleResponseDto#/components/schemas/HandleResponseDto
AccountResponseDto#/components/schemas/AccountResponseDto
SiwsPayloadDto#/components/schemas/SiwsPayloadDto
ErrorResponseDto#/components/schemas/ErrorResponseDto
SignInResponseDto#/components/schemas/SignInResponseDto
EncodedExtrinsicDto#/components/schemas/EncodedExtrinsicDto
SignUpResponseDto#/components/schemas/SignUpResponseDto
WalletLoginRequestDto#/components/schemas/WalletLoginRequestDto
WalletLoginResponseDto#/components/schemas/WalletLoginResponseDto
RetireMsaPayloadResponseDto#/components/schemas/RetireMsaPayloadResponseDto
RetireMsaRequestDto#/components/schemas/RetireMsaRequestDto
TransactionResponse#/components/schemas/TransactionResponse
SchemaDelegation#/components/schemas/SchemaDelegation
Delegation#/components/schemas/Delegation
DelegationResponseV2#/components/schemas/DelegationResponseV2
DelegationResponse#/components/schemas/DelegationResponse
RevokeDelegationPayloadResponseDto#/components/schemas/RevokeDelegationPayloadResponseDto
RevokeDelegationPayloadRequestDto#/components/schemas/RevokeDelegationPayloadRequestDto
HandlePayloadDto#/components/schemas/HandlePayloadDto
HandleRequestDto#/components/schemas/HandleRequestDto
KeysRequestPayloadDto#/components/schemas/KeysRequestPayloadDto
KeysRequestDto#/components/schemas/KeysRequestDto
ItemizedSignaturePayloadDto#/components/schemas/ItemizedSignaturePayloadDto
AddNewPublicKeyAgreementRequestDto#/components/schemas/AddNewPublicKeyAgreementRequestDto

Path Details


[GET]/v1/accounts/siwf

  • Summary
    Get the Sign In With Frequency configuration

Responses

  • 200 Returned SIWF Configuration data

application/json

{
  providerId: string
  siwfUrl: string
  frequencyRpcUrl: string
}

[POST]/v1/accounts/siwf

  • Summary
    Request to Sign In With Frequency

RequestBody

  • application/json
{
  // The wallet login request information
  signIn?: #/components/schemas/SignInResponseDto
  signUp: {
    extrinsics: {
      pallet: string
      extrinsicName: string
      encodedExtrinsic: string
    }[]
    error: {
      message: string
    }
  }
}

Responses

  • 201 Signed in successfully

application/json

{
  referenceId: string
  msaId?: string
  publicKey?: string
}

[GET]/v1/accounts/{msaId}

  • Summary
    Fetch an account given an MSA Id

Responses

  • 200 Found account

application/json

{
  msaId: string
  handle: {
    base_handle: string
    canonical_base: string
    suffix: number
  }
}

[GET]/v1/accounts/account/{accountId}

  • Summary
    Fetch an account given an Account Id

Responses

  • 200 Found account

application/json

{
  msaId: string
  handle: {
    base_handle: string
    canonical_base: string
    suffix: number
  }
}

[GET]/v1/accounts/retireMsa/{accountId}

  • Summary
    Get a retireMsa unsigned, encoded extrinsic payload.

Responses

  • 200 Created extrinsic

application/json

{
  encodedExtrinsic: string
  payloadToSign: string
  accountId: string
}

[POST]/v1/accounts/retireMsa

  • Summary
    Request to retire an MSA ID.

RequestBody

  • application/json
{
  encodedExtrinsic: string
  payloadToSign: string
  accountId: string
  signature: string
}

Responses

  • 201 Created and queued request to retire an MSA ID

application/json

{
  referenceId: string
}

[GET]/v2/delegations/{msaId}

  • Summary
    Get all delegation information associated with an MSA Id

Responses

  • 200 Found delegation information

application/json

{
  msaId: string
  delegations: {
    providerId: string
    schemaDelegations: {
      schemaId: number
      revokedAtBlock?: number
    }[]
    revokedAtBlock?: number
  }[]
}

[GET]/v2/delegations/{msaId}/{providerId}

  • Summary
    Get an MSA's delegation information for a specific provider

Responses

  • 200 Found delegation information

application/json

{
  msaId: string
  delegations: {
    providerId: string
    schemaDelegations: {
      schemaId: number
      revokedAtBlock?: number
    }[]
    revokedAtBlock?: number
  }[]
}

[GET]/v1/delegation/{msaId}

  • Summary
    Get the delegation information associated with an MSA Id

Responses

  • 200 Found delegation information

application/json

{
  providerId: string
  schemaPermissions: {
  }
  revokedAt: {
  }
}

[GET]/v1/delegation/revokeDelegation/{accountId}/{providerId}

  • Summary
    Get a properly encoded RevokeDelegationPayload that can be signed

Responses

  • 200 Returned an encoded RevokeDelegationPayload for signing

application/json

{
  accountId: string
  providerId: string
  encodedExtrinsic: {
  }
  payloadToSign: {
  }
}

[POST]/v1/delegation/revokeDelegation

  • Summary
    Request to revoke a delegation

RequestBody

  • application/json
{
  accountId: string
  providerId: string
  encodedExtrinsic: {
  }
  payloadToSign: {
  }
  signature: {
  }
}

Responses

  • 201 Created and queued request to revoke a delegation

application/json

{
  referenceId: string
}

[POST]/v1/handles

  • Summary
    Request to create a new handle for an account

RequestBody

  • application/json
{
  accountId: string
  payload: {
    baseHandle: string
    expiration: number
  }
  proof: string
}

Responses

  • 200 Handle creation request enqueued

[POST]/v1/handles/change

  • Summary
    Request to change a handle

RequestBody

  • application/json
{
  accountId: string
  payload: {
    baseHandle: string
    expiration: number
  }
  proof: string
}

Responses

  • 200 Handle change request enqueued

[GET]/v1/handles/change/{newHandle}

  • Summary
    Get a properly encoded ClaimHandlePayload that can be signed.

Responses

  • 200 Returned an encoded ClaimHandlePayload for signing

[GET]/v1/handles/{msaId}

  • Summary
    Fetch a handle given an MSA Id

Responses

  • 200 Found a handle

[POST]/v1/keys/add

  • Summary
    Add new control keys for an MSA Id

RequestBody

  • application/json
{
  msaOwnerAddress: string
  msaOwnerSignature: string
  newKeyOwnerSignature: string
  payload: {
    msaId: string
    expiration: number
    newPublicKey: string
  }
}

Responses

  • 200 Found public keys

[GET]/v1/keys/{msaId}

  • Summary
    Fetch public keys given an MSA Id

Responses

  • 200 Found public keys

[GET]/v1/keys/publicKeyAgreements/getAddKeyPayload

  • Summary
    Get a properly encoded StatefulStorageItemizedSignaturePayloadV2 that can be signed.

Parameters(Query)

msaId: string
newKey: string

Responses

  • 200 Returned an encoded StatefulStorageItemizedSignaturePayloadV2 for signing

[POST]/v1/keys/publicKeyAgreements

  • Summary
    Request to add a new public Key

RequestBody

  • application/json
{
  accountId: string
  payload: {
    schemaId: number
    targetHash: number
    expiration: number
    actions: {
    }[]
  }
  proof: string
}

Responses

  • 200 Add new key request enqueued

[GET]/healthz

  • Summary
    Check the health status of the service

Responses

  • 200 Service is healthy

[GET]/livez

  • Summary
    Check the live status of the service

Responses

  • 200 Service is live

[GET]/readyz

  • Summary
    Check the ready status of the service

Responses

  • 200 Service is ready

References

#/components/schemas/WalletLoginConfigResponseDto

{
  providerId: string
  siwfUrl: string
  frequencyRpcUrl: string
}

#/components/schemas/HandleResponseDto

{
  base_handle: string
  canonical_base: string
  suffix: number
}

#/components/schemas/AccountResponseDto

{
  msaId: string
  handle: {
    base_handle: string
    canonical_base: string
    suffix: number
  }
}

#/components/schemas/SiwsPayloadDto

{
  message: string
  signature: string
}

#/components/schemas/ErrorResponseDto

{
  message: string
}

#/components/schemas/SignInResponseDto

{
  siwsPayload: {
    message: string
    signature: string
  }
  error: {
    message: string
  }
}

#/components/schemas/EncodedExtrinsicDto

{
  pallet: string
  extrinsicName: string
  encodedExtrinsic: string
}

#/components/schemas/SignUpResponseDto

{
  extrinsics: {
    pallet: string
    extrinsicName: string
    encodedExtrinsic: string
  }[]
  error: {
    message: string
  }
}

#/components/schemas/WalletLoginRequestDto

{
  // The wallet login request information
  signIn?: #/components/schemas/SignInResponseDto
  signUp: {
    extrinsics: {
      pallet: string
      extrinsicName: string
      encodedExtrinsic: string
    }[]
    error: {
      message: string
    }
  }
}

#/components/schemas/WalletLoginResponseDto

{
  referenceId: string
  msaId?: string
  publicKey?: string
}

#/components/schemas/RetireMsaPayloadResponseDto

{
  encodedExtrinsic: string
  payloadToSign: string
  accountId: string
}

#/components/schemas/RetireMsaRequestDto

{
  encodedExtrinsic: string
  payloadToSign: string
  accountId: string
  signature: string
}

#/components/schemas/TransactionResponse

{
  referenceId: string
}

#/components/schemas/SchemaDelegation

{
  schemaId: number
  revokedAtBlock?: number
}

#/components/schemas/Delegation

{
  providerId: string
  schemaDelegations: {
    schemaId: number
    revokedAtBlock?: number
  }[]
  revokedAtBlock?: number
}

#/components/schemas/DelegationResponseV2

{
  msaId: string
  delegations: {
    providerId: string
    schemaDelegations: {
      schemaId: number
      revokedAtBlock?: number
    }[]
    revokedAtBlock?: number
  }[]
}

#/components/schemas/DelegationResponse

{
  providerId: string
  schemaPermissions: {
  }
  revokedAt: {
  }
}

#/components/schemas/RevokeDelegationPayloadResponseDto

{
  accountId: string
  providerId: string
  encodedExtrinsic: {
  }
  payloadToSign: {
  }
}

#/components/schemas/RevokeDelegationPayloadRequestDto

{
  accountId: string
  providerId: string
  encodedExtrinsic: {
  }
  payloadToSign: {
  }
  signature: {
  }
}

#/components/schemas/HandlePayloadDto

{
  baseHandle: string
  expiration: number
}

#/components/schemas/HandleRequestDto

{
  accountId: string
  payload: {
    baseHandle: string
    expiration: number
  }
  proof: string
}

#/components/schemas/KeysRequestPayloadDto

{
  msaId: string
  expiration: number
  newPublicKey: string
}

#/components/schemas/KeysRequestDto

{
  msaOwnerAddress: string
  msaOwnerSignature: string
  newKeyOwnerSignature: string
  payload: {
    msaId: string
    expiration: number
    newPublicKey: string
  }
}

#/components/schemas/ItemizedSignaturePayloadDto

{
  schemaId: number
  targetHash: number
  expiration: number
  actions: {
  }[]
}

#/components/schemas/AddNewPublicKeyAgreementRequestDto

{
  accountId: string
  payload: {
    schemaId: number
    targetHash: number
    expiration: number
    actions: {
    }[]
  }
  proof: string
}

Configuration

ℹ️ Feel free to adjust your environment variables to taste. This application recognizes the following environment variables:

NameDescriptionRange/TypeRequired?Default
API_PORTHTTP port that the application listens on1025 - 655353000
BLOCKCHAIN_SCAN_INTERVAL_SECONDSHow many seconds to delay between successive scans of the chain for new content (after end of chain is reached)> 012
CACHE_KEY_PREFIXPrefix to use for Redis cache keysstringaccount:
CAPACITY_LIMITMaximum amount of provider capacity this app is allowed to use (per epoch) type: 'percentage' 'amount' value: number (may be percentage, ie '80', or absolute amount of capacity)JSON (example)Y
FREQUENCY_HTTP_URLBlockchain node address resolvable from the client browserhttp(s): URLY
FREQUENCY_URLBlockchain node addresshttp(s): or ws(s): URLY
HEALTH_CHECK_MAX_RETRIESNumber of /health endpoint failures allowed before marking the provider webhook service down>= 020
HEALTH_CHECK_MAX_RETRY_INTERVAL_SECONDSNumber of seconds to retry provider webhook /health endpoint when failing> 064
HEALTH_CHECK_SUCCESS_THRESHOLDMinimum number of consecutive successful calls to the provider webhook /health endpoint before it is marked up again> 010
PROVIDER_ACCESS_TOKENAn optional bearer token authentication to the provider webhookstring
PROVIDER_ACCOUNT_SEED_PHRASESeed phrase for provider MSA control keystringY
PROVIDER_IDProvider MSA IdintegerY
REDIS_URLConnection URL for RedisURLY
TRUST_UNFINALIZED_BLOCKSWhether to examine blocks that have not been finalized when tracking extrinsic completionbooleanfalse
WEBHOOK_BASE_URLBase URL for provider webhook endpointsURLY
WEBHOOK_FAILURE_THRESHOLDNumber of failures allowed in the provider webhook before the service is marked down> 03
WEBHOOK_RETRY_INTERVAL_SECONDSNumber of seconds between provider webhook retry attempts when failing> 010
GRAPH_ENVIRONMENT_TYPEGraph environment type.Mainnet|TestnetPaseoY

Best Practices

  • Secure Authentication: Always use secure methods (e.g., JWT tokens) for authentication to protect user data.
  • Validate Inputs: Ensure all input data is validated to prevent injection attacks and other vulnerabilities.
  • Rate Limiting: Implement rate limiting to protect the service from abuse and ensure fair usage.

Content Publishing Service

The Content Publishing Service allows users to create, post, and manage content on the Frequency network. It supports various content types such as text, images, and videos.

API Reference

Open Full API Reference Page

Path Table

MethodPathDescription
PUT/v1/asset/uploadUpload asset files
POST/v1/content/{userDsnpId}/broadcastCreate DSNP Broadcast for user
POST/v1/content/{userDsnpId}/replyCreate DSNP Reply for user
POST/v1/content/{userDsnpId}/reactionCreate DSNP Reaction for user
PUT/v1/content/{userDsnpId}Update DSNP Content for user
DELETE/v1/content/{userDsnpId}Delete DSNP Content for user
PUT/v1/profile/{userDsnpId}Update a user's Profile
GET/healthzCheck the health status of the service
GET/livezCheck the live status of the service
GET/readyzCheck the ready status of the service
GET/dev/request/{jobId}Get a Job given a jobId
GET/dev/asset/{assetId}Get an Asset given an assetId
POST/dev/dummy/announcement/{queueType}/{count}Create dummy announcement data

Reference Table

Path Details


[PUT]/v1/asset/upload

  • Summary
    Upload asset files

RequestBody

  • multipart/form-data
{
  files?: string[]
}

Responses

  • 2XX

application/json

{
  assetIds?: string[]
}

[POST]/v1/content/{userDsnpId}/broadcast

  • Summary
    Create DSNP Broadcast for user

RequestBody

  • application/json
{
  content: {
    content: string
    published: string
    assets: {
      references: {
        referenceId: string
        height?: number
        width?: number
        duration?: string
      }[]
      name?: string
      href?: string
    }[]
    name?: string
    tag: {
      type: enum[mention, hashtag]
      name?: string
      mentionedId?: string
    }[]
    location: {
      name: string
      accuracy?: number
      altitude?: number
      latitude?: number
      longitude?: number
      radius?: number
      units?: enum[cm, m, km, inches, feet, miles]
    }
  }
}

Responses

  • 2XX

application/json

{
  referenceId: string
}

[POST]/v1/content/{userDsnpId}/reply

  • Summary
    Create DSNP Reply for user

RequestBody

  • application/json
{
  inReplyTo: string
  content: {
    content: string
    published: string
    assets: {
      references: {
        referenceId: string
        height?: number
        width?: number
        duration?: string
      }[]
      name?: string
      href?: string
    }[]
    name?: string
    tag: {
      type: enum[mention, hashtag]
      name?: string
      mentionedId?: string
    }[]
    location: {
      name: string
      accuracy?: number
      altitude?: number
      latitude?: number
      longitude?: number
      radius?: number
      units?: enum[cm, m, km, inches, feet, miles]
    }
  }
}

Responses

  • 2XX

application/json

{
  referenceId: string
}

[POST]/v1/content/{userDsnpId}/reaction

  • Summary
    Create DSNP Reaction for user

RequestBody

  • application/json
{
  emoji: string
  apply: number
  inReplyTo: string
}

Responses

  • 2XX

application/json

{
  referenceId: string
}

[PUT]/v1/content/{userDsnpId}

  • Summary
    Update DSNP Content for user

RequestBody

  • application/json
{
  targetContentHash: string
  targetAnnouncementType: enum[broadcast, reply]
  content: {
    content: string
    published: string
    assets: {
      references: {
        referenceId: string
        height?: number
        width?: number
        duration?: string
      }[]
      name?: string
      href?: string
    }[]
    name?: string
    tag: {
      type: enum[mention, hashtag]
      name?: string
      mentionedId?: string
    }[]
    location: {
      name: string
      accuracy?: number
      altitude?: number
      latitude?: number
      longitude?: number
      radius?: number
      units?: enum[cm, m, km, inches, feet, miles]
    }
  }
}

Responses

  • 2XX

application/json

{
  referenceId: string
}

[DELETE]/v1/content/{userDsnpId}

  • Summary
    Delete DSNP Content for user

RequestBody

  • application/json
{
  targetContentHash: string
  targetAnnouncementType: enum[broadcast, reply]
}

Responses

  • 2XX

application/json

{
  referenceId: string
}

[PUT]/v1/profile/{userDsnpId}

  • Summary
    Update a user's Profile

RequestBody

  • application/json
{
  profile: {
    icon: {
      referenceId: string
      height?: number
      width?: number
      duration?: string
    }[]
    summary?: string
    published?: string
    name?: string
    tag: {
      type: enum[mention, hashtag]
      name?: string
      mentionedId?: string
    }[]
    location: {
      name: string
      accuracy?: number
      altitude?: number
      latitude?: number
      longitude?: number
      radius?: number
      units?: enum[cm, m, km, inches, feet, miles]
    }
  }
}

Responses

  • 2XX

application/json

{
  referenceId: string
}

[GET]/healthz

  • Summary
    Check the health status of the service

Responses

  • 200 Service is healthy

[GET]/livez

  • Summary
    Check the live status of the service

Responses

  • 200 Service is live

[GET]/readyz

  • Summary
    Check the ready status of the service

Responses

  • 200 Service is ready

[GET]/dev/request/{jobId}

  • Summary
    Get a Job given a jobId

  • Description
    ONLY enabled when ENVIRONMENT="dev".

Responses

  • 200

[GET]/dev/asset/{assetId}

  • Summary
    Get an Asset given an assetId

  • Description
    ONLY enabled when ENVIRONMENT="dev".

Responses

  • 2XX

application/octet-stream

{
  "type": "string",
  "format": "binary"
}

[POST]/dev/dummy/announcement/{queueType}/{count}

  • Summary
    Create dummy announcement data

  • Description
    ONLY enabled when ENVIRONMENT="dev".

Responses

  • 201

References

#/components/schemas/FilesUploadDto

{
  files?: string[]
}

#/components/schemas/UploadResponseDto

{
  assetIds?: string[]
}

#/components/schemas/AssetReferenceDto

{
  referenceId: string
  height?: number
  width?: number
  duration?: string
}

#/components/schemas/AssetDto

{
  references: {
    referenceId: string
    height?: number
    width?: number
    duration?: string
  }[]
  name?: string
  href?: string
}

#/components/schemas/TagDto

{
  type: enum[mention, hashtag]
  name?: string
  mentionedId?: string
}

#/components/schemas/LocationDto

{
  name: string
  accuracy?: number
  altitude?: number
  latitude?: number
  longitude?: number
  radius?: number
  units?: enum[cm, m, km, inches, feet, miles]
}

#/components/schemas/NoteActivityDto

{
  content: string
  published: string
  assets: {
    references: {
      referenceId: string
      height?: number
      width?: number
      duration?: string
    }[]
    name?: string
    href?: string
  }[]
  name?: string
  tag: {
    type: enum[mention, hashtag]
    name?: string
    mentionedId?: string
  }[]
  location: {
    name: string
    accuracy?: number
    altitude?: number
    latitude?: number
    longitude?: number
    radius?: number
    units?: enum[cm, m, km, inches, feet, miles]
  }
}

#/components/schemas/BroadcastDto

{
  content: {
    content: string
    published: string
    assets: {
      references: {
        referenceId: string
        height?: number
        width?: number
        duration?: string
      }[]
      name?: string
      href?: string
    }[]
    name?: string
    tag: {
      type: enum[mention, hashtag]
      name?: string
      mentionedId?: string
    }[]
    location: {
      name: string
      accuracy?: number
      altitude?: number
      latitude?: number
      longitude?: number
      radius?: number
      units?: enum[cm, m, km, inches, feet, miles]
    }
  }
}

#/components/schemas/AnnouncementResponseDto

{
  referenceId: string
}

#/components/schemas/ReplyDto

{
  inReplyTo: string
  content: {
    content: string
    published: string
    assets: {
      references: {
        referenceId: string
        height?: number
        width?: number
        duration?: string
      }[]
      name?: string
      href?: string
    }[]
    name?: string
    tag: {
      type: enum[mention, hashtag]
      name?: string
      mentionedId?: string
    }[]
    location: {
      name: string
      accuracy?: number
      altitude?: number
      latitude?: number
      longitude?: number
      radius?: number
      units?: enum[cm, m, km, inches, feet, miles]
    }
  }
}

#/components/schemas/ReactionDto

{
  emoji: string
  apply: number
  inReplyTo: string
}

#/components/schemas/UpdateDto

{
  targetContentHash: string
  targetAnnouncementType: enum[broadcast, reply]
  content: {
    content: string
    published: string
    assets: {
      references: {
        referenceId: string
        height?: number
        width?: number
        duration?: string
      }[]
      name?: string
      href?: string
    }[]
    name?: string
    tag: {
      type: enum[mention, hashtag]
      name?: string
      mentionedId?: string
    }[]
    location: {
      name: string
      accuracy?: number
      altitude?: number
      latitude?: number
      longitude?: number
      radius?: number
      units?: enum[cm, m, km, inches, feet, miles]
    }
  }
}

#/components/schemas/TombstoneDto

{
  targetContentHash: string
  targetAnnouncementType: enum[broadcast, reply]
}

#/components/schemas/ProfileActivityDto

{
  icon: {
    referenceId: string
    height?: number
    width?: number
    duration?: string
  }[]
  summary?: string
  published?: string
  name?: string
  tag: {
    type: enum[mention, hashtag]
    name?: string
    mentionedId?: string
  }[]
  location: {
    name: string
    accuracy?: number
    altitude?: number
    latitude?: number
    longitude?: number
    radius?: number
    units?: enum[cm, m, km, inches, feet, miles]
  }
}

#/components/schemas/ProfileDto

{
  profile: {
    icon: {
      referenceId: string
      height?: number
      width?: number
      duration?: string
    }[]
    summary?: string
    published?: string
    name?: string
    tag: {
      type: enum[mention, hashtag]
      name?: string
      mentionedId?: string
    }[]
    location: {
      name: string
      accuracy?: number
      altitude?: number
      latitude?: number
      longitude?: number
      radius?: number
      units?: enum[cm, m, km, inches, feet, miles]
    }
  }
}

Configuration

ℹ️ Feel free to adjust your environment variables to taste. This application recognizes the following environment variables:

NameDescriptionRange/TypeRequired?Default
API_PORTHTTP port that the application listens on1025 - 655353000
ASSET_EXPIRATION_INTERVAL_SECONDSNumber of seconds to keep completed asset entries in the cache before expiring them> 0Y
ASSET_UPLOAD_VERIFICATION_DELAY_SECONDSBase delay in seconds used for exponential backoff while waiting for uploaded assets to be verified available before publishing a content notice>= 0Y
BATCH_INTERVAL_SECONDSNumber of seconds between publishing batches. This is so that the service waits a reasonable amount of time for additional content to publish before submitting a batch--it represents a trade-off between maximum batch fullness and minimal wait time for content> 0Y
BATCH_MAX_COUNTMaximum number of items that can be submitted in a single batch> 0Y
CACHE_KEY_PREFIXPrefix to use for Redis cache keysstringcontent-publishing-service:
CAPACITY_LIMITMaximum amount of provider capacity this app is allowed to use (per epoch) type: 'percentage' 'amount' value: number (may be percentage, ie '80', or absolute amount of capacity)JSON (example)Y
FILE_UPLOAD_MAX_SIZE_IN_BYTESMax file size (in bytes) allowed for asset upload> 0Y
FREQUENCY_URLBlockchain node addresshttp(s): or ws(s): URLY
IPFS_BASIC_AUTH_SECRETIf using Infura, put auth token here, or leave blank for Kubo RPCstringblank
IPFS_BASIC_AUTH_USERIf using Infura, put Project ID here, or leave blank for Kubo RPCstringblank
IPFS_ENDPOINTURL to IPFS endpointURLY
IPFS_GATEWAY_URLIPFS gateway URL '[CID]' is a token that will be replaced with an actual content IDURL templateY
PROVIDER_ACCOUNT_SEED_PHRASESeed phrase for provider MSA control keystringY
PROVIDER_IDProvider MSA IdintegerY
REDIS_URLConnection URL for RedisURLY

Best Practices

  • Metadata Management: Always ensure metadata is correctly associated with content to maintain data integrity.
  • Content Validation: Validate content to prevent the submission of inappropriate or harmful material.

Content Watcher Service

The Content Watcher Service monitors and retrieves the latest feed state, including content updates, reactions, and other user interactions on the Frequency network. It ensures that applications can stay up-to-date with the latest content and user activity.

API Reference

Open Full API Reference Page

Path Table

MethodPathDescription
POST/v1/scanner/resetReset blockchain scan to a specific block number or offset from the current position
GET/v1/scanner/optionsGet the current watch options for the blockchain content event scanner
POST/v1/scanner/optionsSet watch options to filter the blockchain content scanner by schemas or MSA Ids
POST/v1/scanner/pausePause the blockchain scanner
POST/v1/scanner/startResume the blockchain content event scanner
POST/v1/searchSearch for DSNP content by id, start/end block, and filters
PUT/v1/webhooksRegister a webhook to be called when new content is encountered on the chain
DELETE/v1/webhooksClear all previously registered webhooks
GET/v1/webhooksGet the list of currently registered webhooks
GET/healthzCheck the health status of the service
GET/livezCheck the live status of the service
GET/readyzCheck the ready status of the service

Reference Table

NamePathDescription
ResetScannerDto#/components/schemas/ResetScannerDto
ChainWatchOptionsDto#/components/schemas/ChainWatchOptionsDto
ContentSearchRequestDto#/components/schemas/ContentSearchRequestDto
AnnouncementTypeName#/components/schemas/AnnouncementTypeNameAnnouncement types to send to the webhook
WebhookRegistrationDto#/components/schemas/WebhookRegistrationDto

Path Details


[POST]/v1/scanner/reset

  • Summary
    Reset blockchain scan to a specific block number or offset from the current position

RequestBody

  • application/json
{
  // The block number to reset the scanner to
  blockNumber?: number
  // Number of blocks to rewind the scanner to (from `blockNumber` if supplied; else from latest block)
  rewindOffset?: number
  // Whether to schedule the new scan immediately or wait for the next scheduled interval
  immediate?: boolean
}

Responses

  • 201

[GET]/v1/scanner/options

  • Summary
    Get the current watch options for the blockchain content event scanner

Responses

  • 200

application/json

{
  schemaIds?: number[]
  dsnpIds?: string[]
}

[POST]/v1/scanner/options

  • Summary
    Set watch options to filter the blockchain content scanner by schemas or MSA Ids

RequestBody

  • application/json
{
  schemaIds?: number[]
  dsnpIds?: string[]
}

Responses

  • 201

[POST]/v1/scanner/pause

  • Summary
    Pause the blockchain scanner

Responses

  • 201

[POST]/v1/scanner/start

  • Summary
    Resume the blockchain content event scanner

Parameters(Query)

immediate?: boolean

Responses

  • 201

[POST]/v1/search

  • Summary
    Search for DSNP content by id, start/end block, and filters

RequestBody

  • application/json
{
  // An optional client-supplied reference ID by which it can identify the result of this search
  clientReferenceId?: string
  // The block number to search (backward) from
  startBlock?: number
  // The number of blocks to scan (backwards)
  blockCount: number
  // The schemaIds/dsnpIds to filter by
  filters?: #/components/schemas/ChainWatchOptionsDto
  // A webhook URL to be notified of the results of this search
  webhookUrl: string
}

Responses

  • 200 Returns a jobId to be used to retrieve the results

application/json

{
  "type": "string"
}

[PUT]/v1/webhooks

  • Summary
    Register a webhook to be called when new content is encountered on the chain

RequestBody

  • application/json
{
  // Webhook URL
  url: string
  // Announcement types to send to the webhook
  announcementTypes?: enum[tombstone, broadcast, reply, reaction, profile, update][]
}

Responses

  • 200

[DELETE]/v1/webhooks

  • Summary
    Clear all previously registered webhooks

Responses

  • 200

[GET]/v1/webhooks

  • Summary
    Get the list of currently registered webhooks

Responses

  • 200 Returns a list of registered webhooks

application/json

{
  // Webhook URL
  url: string
  // Announcement types to send to the webhook
  announcementTypes?: enum[tombstone, broadcast, reply, reaction, profile, update][]
}[]

[GET]/healthz

  • Summary
    Check the health status of the service

Responses

  • 200 Service is healthy

[GET]/livez

  • Summary
    Check the live status of the service

Responses

  • 200 Service is live

[GET]/readyz

  • Summary
    Check the ready status of the service

Responses

  • 200 Service is ready

References

#/components/schemas/ResetScannerDto

{
  // The block number to reset the scanner to
  blockNumber?: number
  // Number of blocks to rewind the scanner to (from `blockNumber` if supplied; else from latest block)
  rewindOffset?: number
  // Whether to schedule the new scan immediately or wait for the next scheduled interval
  immediate?: boolean
}

#/components/schemas/ChainWatchOptionsDto

{
  schemaIds?: number[]
  dsnpIds?: string[]
}

#/components/schemas/ContentSearchRequestDto

{
  // An optional client-supplied reference ID by which it can identify the result of this search
  clientReferenceId?: string
  // The block number to search (backward) from
  startBlock?: number
  // The number of blocks to scan (backwards)
  blockCount: number
  // The schemaIds/dsnpIds to filter by
  filters?: #/components/schemas/ChainWatchOptionsDto
  // A webhook URL to be notified of the results of this search
  webhookUrl: string
}

#/components/schemas/AnnouncementTypeName

{
  "type": "string",
  "description": "Announcement types to send to the webhook",
  "enum": [
    "tombstone",
    "broadcast",
    "reply",
    "reaction",
    "profile",
    "update"
  ]
}

#/components/schemas/WebhookRegistrationDto

{
  // Webhook URL
  url: string
  // Announcement types to send to the webhook
  announcementTypes?: enum[tombstone, broadcast, reply, reaction, profile, update][]
}

Configuration

ℹ️ Feel free to adjust your environment variables to taste. This application recognizes the following environment variables:

NameDescriptionRange/TypeRequired?Default
API_PORTHTTP port that the application listens on1025 - 655353000
BLOCKCHAIN_SCAN_INTERVAL_SECONDSHow many seconds to delay between successive scans of the chain for new content (after end of chain is reached)> 012
CACHE_KEY_PREFIXPrefix to use for Redis cache keysstringcontent-watcher:
FREQUENCY_URLBlockchain node addresshttp(s): or ws(s): URLY
IPFS_BASIC_AUTH_SECRETIf required for read requests, put Infura auth token here, or leave blank for default Kubo RPCstringNblank
IPFS_BASIC_AUTH_USERIf required for read requests, put Infura Project ID here, or leave blank for default Kubo RPCstringNblank
IPFS_ENDPOINTURL to IPFS endpointURLY
IPFS_GATEWAY_URLIPFS gateway URL '[CID]' is a token that will be replaced with an actual content IDURL templateY
QUEUE_HIGH_WATERMax number of jobs allowed on the queue before blockchain scan will be paused to allow queue to drain>= 1001000
REDIS_URLConnection URL for RedisURLY
STARTING_BLOCKBlock number from which the service will start scanning the chain> 01
WEBHOOK_FAILURE_THRESHOLDNumber of failures allowed in the provider webhook before the service is marked down> 03
WEBHOOK_RETRY_INTERVAL_SECONDSNumber of seconds between provider webhook retry attempts when failing> 010

Best Practices

  • Efficient Polling: Implement efficient polling mechanisms to minimize load on the service.
  • Webhook Security: Secure webhooks by verifying the source of incoming requests.
  • Rate Limiting: Apply rate limiting to prevent abuse and ensure fair usage of the service.

Graph Service

The Graph Service manages the social graphs, including follow/unfollow actions, blocking users, and other social interactions. It allows applications to maintain and query the social connections between users on the Frequency network.

API Reference

Open Full API Reference Page

Path Table

MethodPathDescription
POST/v1/graphs/getGraphsFetch graphs for specified MSA Ids and Block Number
PUT/v1/graphsRequest an update to a given user's graph
GET/v1/webhooksGet all registered webhooks
PUT/v1/webhooksWatch graphs for specified dsnpIds and receive updates
DELETE/v1/webhooksDelete all registered webhooks
GET/v1/webhooks/users/{msaId}Get all registered webhooks for a specific MSA Id
DELETE/v1/webhooks/users/{msaId}Delete all webhooks registered for a specific MSA
GET/v1/webhooks/urlsGet all webhooks registered to the specified URL
DELETE/v1/webhooks/urlsDelete all MSA webhooks registered with the given URL
GET/healthzCheck the health status of the service
GET/livezCheck the live status of the service
GET/readyzCheck the ready status of the service

Reference Table

Path Details


[POST]/v1/graphs/getGraphs

  • Summary
    Fetch graphs for specified MSA Ids and Block Number

RequestBody

  • application/json
{
  dsnpIds?: string[]
  // Graph type to query (public or private)
  privacyType: enum[private, public]
  graphKeyPairs: {
    // Public graph encryption key as a hex string (prefixed with "0x")
    publicKey: string
    // Private graph encryption key as a hex string (prefixed with "0x")
    privateKey: string
    // Key type of graph encryption keypair (currently only X25519 supported)
    keyType: enum[X25519]
  }[]
}

Responses

  • 200 Graphs retrieved successfully

application/json

{
  // MSA Id that is the owner of the graph represented by the graph edges in this object
  dsnpId: string
  dsnpGraphEdges: {
    // MSA Id of the user represented by this graph edge
    userId: string
    // Block number when connection represented by this graph edge was created
    since: number
  }[]
}[]

[PUT]/v1/graphs

  • Summary
    Request an update to a given user's graph

RequestBody

  • application/json
{
  // MSA Id that owns the connections represented in this object
  dsnpId: string
  // Array of connections known to the Provider for ths MSA referenced in this object
  connections: #/components/schemas/ConnectionDtoWrapper
  graphKeyPairs: {
    // Public graph encryption key as a hex string (prefixed with "0x")
    publicKey: string
    // Private graph encryption key as a hex string (prefixed with "0x")
    privateKey: string
    // Key type of graph encryption keypair (currently only X25519 supported)
    keyType: enum[X25519]
  }[]
  // Optional URL of a webhook to invoke when the request is complete
  webhookUrl?: string
}

Responses

  • 201 Graph update request created successfully

application/json

{
  // Reference ID by which the results/status of a submitted GraphChangeRequest may be retrieved
  referenceId: string
}

[GET]/v1/webhooks

  • Summary
    Get all registered webhooks

Responses

  • 200 Retrieved all registered webhooks

[PUT]/v1/webhooks

  • Summary
    Watch graphs for specified dsnpIds and receive updates

RequestBody

  • application/json
{
  dsnpIds?: string[]
  // Webhook URL to call when graph changes for the referenced MSAs are detected
  webhookEndpoint: string
}

Responses

  • 200 Successfully started watching graphs

[DELETE]/v1/webhooks

  • Summary
    Delete all registered webhooks

Responses

  • 200 Removed all registered webhooks

[GET]/v1/webhooks/users/{msaId}

  • Summary
    Get all registered webhooks for a specific MSA Id

Parameters(Query)

includeAll?: boolean

Responses

  • 200 Retrieved all registered webhooks for the given MSA Id

[DELETE]/v1/webhooks/users/{msaId}

  • Summary
    Delete all webhooks registered for a specific MSA

Responses

  • 200 Removed all registered webhooks for the specified MSA

[GET]/v1/webhooks/urls

  • Summary
    Get all webhooks registered to the specified URL

Parameters(Query)

url: string

Responses

  • 200 Retrieved all webhooks registered to the specified URL

[DELETE]/v1/webhooks/urls

  • Summary
    Delete all MSA webhooks registered with the given URL

Parameters(Query)

url: string

Responses

  • 200 Removed all webhooks registered to the specified URL

[GET]/healthz

  • Summary
    Check the health status of the service

Responses

  • 200 Service is healthy

[GET]/livez

  • Summary
    Check the live status of the service

Responses

  • 200 Service is live

[GET]/readyz

  • Summary
    Check the ready status of the service

Responses

  • 200 Service is ready

References

#/components/schemas/GraphKeyPairDto

{
  // Public graph encryption key as a hex string (prefixed with "0x")
  publicKey: string
  // Private graph encryption key as a hex string (prefixed with "0x")
  privateKey: string
  // Key type of graph encryption keypair (currently only X25519 supported)
  keyType: enum[X25519]
}

#/components/schemas/GraphsQueryParamsDto

{
  dsnpIds?: string[]
  // Graph type to query (public or private)
  privacyType: enum[private, public]
  graphKeyPairs: {
    // Public graph encryption key as a hex string (prefixed with "0x")
    publicKey: string
    // Private graph encryption key as a hex string (prefixed with "0x")
    privateKey: string
    // Key type of graph encryption keypair (currently only X25519 supported)
    keyType: enum[X25519]
  }[]
}

#/components/schemas/DsnpGraphEdgeDto

{
  // MSA Id of the user represented by this graph edge
  userId: string
  // Block number when connection represented by this graph edge was created
  since: number
}

#/components/schemas/UserGraphDto

{
  // MSA Id that is the owner of the graph represented by the graph edges in this object
  dsnpId: string
  dsnpGraphEdges: {
    // MSA Id of the user represented by this graph edge
    userId: string
    // Block number when connection represented by this graph edge was created
    since: number
  }[]
}

#/components/schemas/ConnectionDto

{
  // MSA Id representing the target of this connection
  dsnpId: string
  // Indicator connection type (public or private)
  privacyType: enum[private, public]
  // Indicator of the direction of this connection
  direction: enum[connectionTo, connectionFrom, bidirectional, disconnect]
  // Indicator of the type of connection (follow or friendship)
  connectionType: enum[follow, friendship]
}

#/components/schemas/ConnectionDtoWrapper

{
  data: {
    // MSA Id representing the target of this connection
    dsnpId: string
    // Indicator connection type (public or private)
    privacyType: enum[private, public]
    // Indicator of the direction of this connection
    direction: enum[connectionTo, connectionFrom, bidirectional, disconnect]
    // Indicator of the type of connection (follow or friendship)
    connectionType: enum[follow, friendship]
  }[]
}

#/components/schemas/ProviderGraphDto

{
  // MSA Id that owns the connections represented in this object
  dsnpId: string
  // Array of connections known to the Provider for ths MSA referenced in this object
  connections: #/components/schemas/ConnectionDtoWrapper
  graphKeyPairs: {
    // Public graph encryption key as a hex string (prefixed with "0x")
    publicKey: string
    // Private graph encryption key as a hex string (prefixed with "0x")
    privateKey: string
    // Key type of graph encryption keypair (currently only X25519 supported)
    keyType: enum[X25519]
  }[]
  // Optional URL of a webhook to invoke when the request is complete
  webhookUrl?: string
}

#/components/schemas/GraphChangeRepsonseDto

{
  // Reference ID by which the results/status of a submitted GraphChangeRequest may be retrieved
  referenceId: string
}

#/components/schemas/WatchGraphsDto

{
  dsnpIds?: string[]
  // Webhook URL to call when graph changes for the referenced MSAs are detected
  webhookEndpoint: string
}

Configuration

ℹ️ Feel free to adjust your environment variables to taste. This application recognizes the following environment variables:

NameDescriptionRange/TypeRequired?Default
API_PORTHTTP port that the application listens on1025 - 655353000
BLOCKCHAIN_SCAN_INTERVAL_SECONDSHow many seconds to delay between successive scans of the chain (after end of chain is reached)> 0180
CACHE_KEY_PREFIXPrefix to use for Redis cache keysstringcontent-watcher:
CAPACITY_LIMITMaximum amount of provider capacity this app is allowed to use (per epoch) type: 'percentage' 'amount' value: number (may be percentage, ie '80', or absolute amount of capacity)JSON (example)Y
DEBOUNCE_SECONDSNumber of seconds to retain pending graph updates in the Redis cache to avoid redundant fetches from the chain>= 0
FREQUENCY_URLBlockchain node addresshttp(s): or ws(s): URLY
GRAPH_ENVIRONMENT_TYPEGraph environment type.Mainnet|TestnetPaseoY
HEALTH_CHECK_MAX_RETRIESNumber of /health endpoint failures allowed before marking the provider webhook service down>= 020
HEALTH_CHECK_MAX_RETRY_INTERVAL_SECONDSNumber of seconds to retry provider webhook /health endpoint when failing> 064
HEALTH_CHECK_SUCCESS_THRESHOLDMinimum number of consecutive successful calls to the provider webhook /health endpoint before it is marked up again> 010
PROVIDER_ACCOUNT_SEED_PHRASESeed phrase for provider MSA control keystringY
PROVIDER_IDProvider MSA IdintegerY
QUEUE_HIGH_WATERMax number of jobs allowed on the 'graphUpdateQueue' before blockchain scan will be paused to allow queue to drain>= 1001000
RECONNECTION_SERVICE_REQUIREDWhether to instantiate/activate reconnection-service featurestrue/false
REDIS_URLConnection URL for RedisURLY

The following environment variables are only relevant if RECONNECTION_SERVICE_REQUESTED is 'true':

NameDescriptionRange/TypeRequired?Default
CONNECTIONS_PER_PROVIDER_RESPONSE_PAGENumber of connection/page to request when requesting provider connections from webhook> 0100
PROVIDER_ACCESS_TOKENAn optional bearer token authentication to the provider webhookstring
PROVIDER_BASE_URLBase URL for provider webhook endpointsURLY
WEBHOOK_FAILURE_THRESHOLDNumber of failures allowed in the provider webhook before the service is marked down> 03
WEBHOOK_RETRY_INTERVAL_SECONDSNumber of seconds between provider webhook retry attempts when failing> 010

Best Practices

  • Data Integrity: Ensure the integrity of social graph data by implementing robust validation checks.
  • Efficient Queries: Optimize queries to handle large social graphs efficiently.
  • User Privacy: Protect user privacy by ensuring that graph data is only accessible to authorized entities.

Run

Coming soon...

Deployment

Coming soon...

Security

Coming soon...

Performance

Coming soon...

Scalability

Coming soon...

FAQ

Coming soon...

Support Channels

Need help with Gateway or working through the Frequency ecosystem? There are many different options to meet your needs.

GitHub Issues

Checking and creating a GitHub issue is a easy place to start if you want to ask a question or file a bug report or documentation issue you find.

Frequency Discord

Frequency has a Discord where you can discuss Gateway and connect with the Frequency community.

Direct Partnership

Gateway is built by Project Liberty, a contributor to the Frequency ecosystem. If you want more help or just to connect, contact hello@projectliberty.io.

Community Resources

Gateway

All Gateway code is open source, and you are welcome to participate in its development.

Many of the Gateway related tools are also open source:

Frequency

Frequency is built using the Polkadot SDK. Most Polkadot SDK (also called Substrate) tooling works with Frequency.

IPFS

IPFS (the InterPlanetary File System) is a peer-to-peer network and protocol designed to make the web faster, safer, and more open. It uses "content-based addressing" which allows content to move to different servers and act as a distributed CDN on demand. While most users rely on providers to maintain the availability of files, users may move services and providers may help them to maintain the availability of their content.

DSNP

Gateway is built using DSNP (Decentralized Social Media Protocol).

Project Liberty

Project Liberty is a contributor to the Frequency ecosystem and the maintainer of the open source Gateway tool.