Skip to content

Run your XMTP Gateway Service

An XMTP Gateway Service is a proxy that pays for and forwards messages to the XMTP Broadcast Network on behalf of your users. Think of it as your app or agent's payment gateway for messaging.

Behind the scenes, your XMTP Gateway Service handles all the complexity of blockchain payments so your users (and you) don't have to think about it.

  • For browser and mobile client apps, you host your XMTP Gateway Service on your infrastructure because it contains your payer wallet's private key.

  • For agents and Node.js apps, there is no need to run a separate XMTP Gateway Service. The XMTP Gateway Service will be built into the XMTP Node and Agent SDKs.

XMTP provides a standard implementation of an XMTP Gateway Service that you can extend to meet your unique needs. Once your XMTP Gateway Service is deployed, you will need to include the payer_service_address when creating any XMTP client in your app or agent.

Get started

Every app and agent needs an XMTP Gateway Service.

For browser and mobile client apps

You must run the XMTP Gateway Service written in Go. You have two options:

  • For production: Use the example gateway service repository as a starting point to build your own custom gateway with authentication
  • For testing only: Use the prebuilt Docker image (xmtp/xmtpd-gateway:main) which authorizes all requests without authentication

For detailed implementation steps, see Deploy your XMTP Gateway Service.

For agents and Node.js apps

No need to run a separate XMTP Gateway Service. The XMTP Gateway Service will be built into the XMTP Node and Agent SDKs—COMING SOON.

TypeScript
// Automatic gateway included, no separate service needed
const client = await Client.create(wallet, {
  env: 'mainnet',
});

A minimal example

This is all the code you need to create the most bare bones XMTP Gateway Service. The service will configure itself from command line flags or environment variables, and begin receiving traffic on ports 5050 and 5055.

This minimal example will authorize every request it receives with no limits. In a real production app, you will want to make sure that you only approve requests from your own users.

Go
package main
 
import (
 "context"
 "log"
 "slices"
 
 "github.com/xmtp/xmtpd/pkg/gateway"
)
 
func main() {
 // This will gather all the config from environment variables and flags
 gatewayService, err := gateway.NewGatewayServiceBuilder(gateway.MustLoadConfig()).
  Build()
 if err != nil {
  log.Fatalf("Failed to build gateway service: %v", err)
 }
 
 gatewayService.WaitForShutdown()
}
 

Configure your XMTP Gateway Service

You can provide the configuration options for your XMTP Gateway Service either directly in your code, via command line flag, or through environment variables.

NameRequiredCommand line flagEnvironment variableInfo
Payer Private Keytrue--payer.private-keyXMTPD_PAYER_PRIVATE_KEYThe secp256k1 private key of the Ethereum Account you have already funded in the Funding Portal. Used to sign transactions and pay fees from your payer allowance in the Payer Registry smart contract.
App Chain RPC URLtrue--contracts.app-chain.rpc-urlXMTPD_APP_CHAIN_RPC_URLThe RPC URL of your Blockchain RPC provider's endpoint for XMTP Chain
Settlement Chain RPC URLtrue--contracts.settlement-chain.rpc-urlXMTPD_SETTLEMENT_CHAIN_RPC_URLThe RPC URL of your Blockchain RPC provider's endpoint for the Base chain
App Chain WSS URLtrue--contracts.app-chain.wss-urlXMTPD_APP_CHAIN_WSS_URLThe websocket URL of your Blockchain RPC provider's endpoint for XMTP Chain
Settlement Chain WSS URLtrue--contracts.settlement-chain.wss-urlXMTPD_SETTLEMENT_CHAIN_WSS_URLThe websocket URL of your Blockchain RPC provider's endpoint for the Base chain
Environmenttrue--contracts.environmentXMTPD_CONTRACTS_ENVIRONMENTThe environment your XMTP Gateway Service will run in. Valid values are anvil, testnet, and mainnet
Redis Connection Stringfalse--redis.connection-stringXMTPD_REDIS_CONNECTION_STRINGThe connection string for your Redis instance

Metrics and observability

If the XMTP Gateway Service is configured with the --metrics.enable flag, it will expose a Prometheus endpoint at /metrics on port 8008 which can be ingested by any compatible monitoring system.

Allocate funds for messaging

The private key for your XMTP Gateway Service must belong to a payer wallet that has allocated funds for messaging in the XMTP Funding Portal.

To learn more, see Fund your app or agent to send messages with XMTP.

Authenticate users

You can think of the XMTP Gateway Service as an extension of your client app. If you already have a system for authenticating user requests in your app, you should use it in your XMTP Gateway Service. For example, many apps use JSON Web Tokens (JWTs) to authenticate client requests to servers.

You can use any authentication scheme you like to authenticate requests from your client to the XMTP Gateway Service.

In your client—COMING SOON

When creating an XMTP client, you will be able to optionally provide an gatewayAuthTokenFetcher as part of client configuration.

The value returned by this function will be included in all client requests to the XMTP Gateway Service. The fetchAuthToken function will be called before the first request is made to the XMTP Gateway Service, and after any request to the XMTP Gateway Service fails due to a PermissionDenied error.

In the XMTP Gateway Service

The GatewayServiceBuilder allows you to provide an IdentityFn that you can use to identify your users. The function is expected to return a gateway.Identity struct, which identifies the user in a way that is unique to your app.

This identity will then be used for rate limiting, and will be passed to your AuthorizePublishFn as additional context.

IP address
//  We provide a simple implementation that uses the client's IP address to identify users. For a production application, you should limit requests to only users actually authenticated in your application.
package main
 
import (
 "context"
 "log"
 "slices"
 
 "github.com/xmtp/xmtpd/pkg/gateway"
)
 
func main() {
 // This will gather all the config from environment variables and flags
 gatewayService, err := gateway.NewGatewayServiceBuilder(gateway.MustLoadConfig()).
  // The gateway service will use the IP address of the client as the identity by default
  Build()
 if err != nil {
  log.Fatalf("Failed to build gateway service: %v", err)
 }
 
 gatewayService.WaitForShutdown()
}
 

Authorize requests

Now that you have an identity for the caller of your API, you can use it to authorize requests. We provide some helpers to handle common authorization patterns, such as rate limiting.

You can add multiple authorizers to your XMTP Gateway Service. All authorizers will be called in parallel. The first authorizer (based on the order they are added) that returns false or an error will cause the request to be rejected.

IP Allowlist
package main
 
import (
 "context"
 "log"
 "slices"
 
 "github.com/xmtp/xmtpd/pkg/payer"
)
 
func main() {
 payerService, err := payer.NewPayerServiceBuilder(payer.MustLoadConfig()).
  WithAuthorizers(func(ctx context.Context, identity payer.Identity, req payer.PublishRequest) (bool, error) {
   // A simple authorization function that allows only the IP 127.0.0.1
   allowedIPs := []string{"127.0.0.1"}
   if !slices.Contains(allowedIPs, identity.Identity) {
    return false, payer.ErrUnauthorized
   }
   return true, nil
  }).
  Build() // This will gather all the config from environment variables and flags
 if err != nil {
  log.Fatalf("Failed to build XMTP Gateway Service: %v", err)
 }
 
 err = payerService.Serve(context.Background())
 if err != nil {
  log.Fatalf("Failed to serve XMTP Gateway Service: %v", err)
 }
}

Deploy your XMTP Gateway Service

Deploy the XMTP Gateway Service on your infrastructure of choice, such as a container hosting service ($25-50/month minimum).

For production deployments

Use the example gateway service repository as your starting point:

  1. Fork or clone the repository
  2. Customize the authentication logic for your app
  3. Build your own Docker image from the included Dockerfile
  4. Deploy your custom image to your hosting provider

Additional recommendations

The system is able to run without any external dependencies, but we recommend configuring a Redis instance to use for nonce management and rate limiting.

If your XMTP Gateway Service goes down, messages will queue until it comes back online. Build redundancy, if needed.

For testing only

You can use the prebuilt Docker image for local development and testing:

Bash
docker run -p 5050:5050 -p 5055:5055 -e XMTPD_PAYER_PRIVATE_KEY=... xmtp/xmtpd-gateway:main

Test your XMTP Gateway Service

Here are some high priority scenarios to test:

  • Deploy and test XMTP Gateway Service
    • Not needed for agents and Node.js apps using the XMTP Node or Agent SDKs, which will provide a built-in XMTP Gateway Service.
  • Verify authentication works properly
  • Test with expected message volumes
  • Monitor resource usage and costs
  • Simulate failure scenarios

You can test on Base Sepolia, App Chain testnet, and Broadcast Network testnet. They all run identical contracts so you can dry-run funding and messaging.

To get testnet USDC, use https://faucet.circle.com/, which provides 10 USDC per hour.

Testing timeline

Until November 1: Testnet-only period

  • Use testnet USDC (no real cost)
  • Validate XMTP Gateway Service setup
  • Test authentication flows
  • Ensure infrastructure scales

After November 1: Full mainnet testing

  • Funding Portal accepts real USDC
  • Production environment testing
  • Fee validation with real funds
  • Final integration checks

XMTP Gateway Service flows

The following sequence diagrams illustrate the XMTP Gateway Service's role in the following key flows.

Flow for sending a message to the XMTP Broadcast Network

Flow for sending a message to the XMTP App Chain