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:
Customer creates a forwarding address linked to their Stackup wallet and end user attributes.
Customer distributes forwarding address to their end user.
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.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 |
---|---|
| Your wallet's address |
Request Body
Field | Type | Description |
---|---|---|
|
| Optional name field for the intended sender. |
|
| Optional bio for the intended sender. |
|
| 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 |
---|---|
| Your wallet's address |
| 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 |
---|---|---|
|
| Optional name field for the intended sender. |
|
| Optional bio for the intended sender. |
|
| 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 |
---|---|
| 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 |
---|---|
| Your wallet's address |
| 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.