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. Choose the option that works best for you:

Option 1: Basic Docker image (No Go knowledge required)

  • XMTP provides a Docker image that works out of the box
  • Authorizes all requests (add authentication for production)
  • Suitable for testing

Option 2: Custom implementation (Go knowledge required)

  • Start with XMTP's Go implementation
  • Add your own authentication logic
  • Implement custom rate limiting
  • Required for apps with authentication needs

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 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 local, testnet, and mainnet
Enable Redistrue--redis.enableXMTPD_REDIS_ENABLEUse Redis for nonce management and rate limiting.
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).

We provide a Docker image that corresponds to the bare bones example above that you can run with the appropriate environment variables set in any hosting provider that supports Docker.

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

Most production apps will require some level of customization to authorize user requests. We provide a sample Dockerfile in the xmtpd dev/docker directory that you can use as a starting point.

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.

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