Forwarding Address API

Prev Next

Forwarding addresses allows customers to spin up non-custodial and attributable routes from a proxy address to the Stackup wallet. This is useful for cases where customers are expecting incoming payments from many users via an arbitrary source and require specific tracking for each user's payment status.

An "arbitrary source" is defined by a user transferring to a customer's wallet via a non Stackup interface. For example transferring directly via a CEX or other non-custodial wallets where there is no control of call data for attribution.

Overview

Forwarding addresses have the following flow:

  1. Customer creates a forwarding address linked to their Stackup wallet and end user attributes.

  2. Customer distributes forwarding address to their end user.

  3. When an end user does a transfer to the forwarding address it notifies the customer via a webhook (push). Alternatively, customers can also pull forwarding data from a GET API.

  4. A sweep from forwarding addresses to the Stackup wallet occur automatically.

Prerequisites

  • An API token

  • A Stackup wallet address

  • Optional: configured webhook if push events are required

Endpoints

Create a new forwarding address

Create a unique and deterministic address for receiving native or ERC20 tokens and asynchronously swept to an associated wallet.

POST /v1/wallet/{walletAddress}/forwarding-address

URL Parameters

Parameter

Description

walletAddress

Your wallet's address

Request Body

Field

Type

Description

name

string or undefined

Optional name field for the intended sender.

description

string or undefined

Optional bio for the intended sender.

tags

Array<string> or undefined

Optional miscellaneous tags for grouping this forwarding address.

Example Request

{
   "name":"John Doe",
   "description":"Customer",
   "tags":[
      "USDC",
      "US",
      "Ethereum"
   ]
}

Example Response

{
    "forwardingAddress": "0x....",
    "factory": "0x...",
    "factoryData": "0x..."
}

Update Forwarding Address

Apply updates the the name, description, or tags to a current forwarding address.

PATCH /v1/wallet/{walletAddress}/forwarding-address/{forwardingAddress}

URL Parameters

Parameter

Description

walletAddress

Your wallet's address

forwardingAddress

Your generated forwarding address

Request Body

Note that null values will unset the field and undefined values will leave the field as is.

Field

Type

Description

name

string, null, or undefined

Optional name field for the intended sender.

description

string, null, or undefined

Optional bio for the intended sender.

tags

Array<string>, null, or undefined

Optional miscellaneous tags for grouping this forwarding address.

Example Request

{
   "name":"NEW NAME",
   "description": "NEW DESCRIPTION",
   "tags": ["NEW_TAGS"]
}

Example Response

{
  "success": true
}

List forwarding address for wallet

Returns a list of all created forwarding addresses for your wallet.

GET /v1/wallet/{walletAddress}/forwarding-address

URL Parameters

Parameter

Description

walletAddress

Your wallet's address

Example Response

[
   {
      "walletAddress":"0xffff...",
      "forwardingAddress":"0xdddd...",
      "name":"John",
      "description":"service fee",
      "tags":[
         "USDC",
         "order-123456789",
         "uuid-123456789"
      ],
      "factory":"0x...",
      "factoryData":"0x..."
   },
   {
      "walletAddress":"0xffff...",
      "forwardingAddress":"0xaaa...",
      "name":"Alice",
      "description":"service fee",
      "tags":[
         "USDC",
         "order-987654321",
         "uuid-987654321"
      ],
      "factory":"0x...",
      "factoryData":"0x..."
   }
]

Get single forwarding address with payments

Returns details and payment history of a single forwarding address for your wallet.

GET /v1/wallet/{walletAddress}/forwarding-address/{forwardingAddress}

URL Parameters

Parameter

Description

walletAddress

Your wallet's address

forwardingAddress

Your generated forwarding address

Example Response

{
   "walletAddress":"0xffff...",
   "forwardingAddress":"0xdddd...",
   "name":"John",
   "description":"service fee",
   "tags":[
      "USDC",
      "order-123456789",
      "uuid-123456789"
   ],
   "factory":"0x...",
   "factoryData":"0x...",
   "receivedPayments":[
      {
         "id":"123456",
         "senderAddress":"0xaaaaa...",
         "txHash":"0x...",
         "txTimestamp":"2024-08-08T12:34:56Z",
         "token":"USDC",
         "value":100,
         "chainID":"1"
      }
   ]
}

Notifications on receive

If webhook is configured, the following event will be pushed on all incoming payments to a forwarding address.

{
   "id":"evt_123",
   "type":"forwarding-address.deposited",
   "version":"1.0",
   "timestamp":"2024-08-08T12:34:56Z",
   "data":{
      "walletAddress":"0xffff...",
      "forwardingAddress":"0xdddd...",
      "name":"John",
      "description":"service fee",
      "factory":"0x...",
      "factoryData":"0x...",
      "tags":[
         "USDC",
         "order-123456789",
         "uuid-123456789"
      ],
      "receivedPayment":{
         "id":"123456",
         "senderAddress":"0xaaaaa...",
         "txHash":"0x...",
         "txTimestamp":"1757131531",
         "token":"USDC",
         "value":100,
         "chainID":"1"
      }
   }
}

Forwarding Address architecture

Every instance of a forwarding address is backed by a ERC-1167 minimal proxy contract with the following interface.

interface IForwardingAddress {
    function receiver() external view returns (address);
    function initialize(address payable aReceiver) external;
    
    // A zero address for the input will sweep native ETH
    function sweep(address token) external;
}

When a request is made to create a new forwarding address, the API returns a deterministic address based on the customer's Stackup wallet address (i.e. the receiver) and a random salt.

During the sweep, our system will automatically deploy the minimal proxy (if not yet deployed) and call sweep to transfer all assets to the destination.

Note that both deployment and sweep actions are permissionless. The sweep function will always transfer max balance of the specified token to the initialized receiver address.

For a full deep dive on the code, see the following repository at github.com/stackup-wallet/forwarding-address.