Recover stuck assets
curl --request POST \
--url https://api-partner.houdiniswap.com/v2/exchanges/multi/recovery \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"multiId": "<string>"
}
'import requests
url = "https://api-partner.houdiniswap.com/v2/exchanges/multi/recovery"
payload = { "multiId": "<string>" }
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({multiId: '<string>'})
};
fetch('https://api-partner.houdiniswap.com/v2/exchanges/multi/recovery', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-partner.houdiniswap.com/v2/exchanges/multi/recovery",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'multiId' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api-partner.houdiniswap.com/v2/exchanges/multi/recovery"
payload := strings.NewReader("{\n \"multiId\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api-partner.houdiniswap.com/v2/exchanges/multi/recovery")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"multiId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-partner.houdiniswap.com/v2/exchanges/multi/recovery")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"multiId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"saAddress": "0x3aF1c90b5E2d7B4a8c6E9f0a1B2c3D4e5F607182",
"assets": [
{
"tokenAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7",
"tokenSymbol": "USDT",
"decimals": 6,
"balance": "1000000000",
"sourceHoudiniIds": [
"hxK7mQp2"
]
}
],
"transactions": [
{
"houdiniIds": [
"hxK7mQp2"
],
"txData": {
"userOpHash": "0x7b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f90a",
"to": "0xdac17f958d2ee523a2206206994597c13d831ec7",
"data": "0xa9059cbb000000000000000000000000b7de6b6eebf7401afea5a49d6405c9048fef2d40",
"value": "0",
"chainId": 1,
"tokenAmount": "1000000000"
}
}
]
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"fields": {},
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}Bundler EVM
Recover stuck assets
Finds failed EVM batches for a wallet and returns pre-built withdrawal UserOps. Use this once retry is no longer possible.
- 404 means nothing to withdraw — no failed swap for this
multiId, or the smart account no longer holds those tokens
POST
/
exchanges
/
multi
/
recovery
Recover stuck assets
curl --request POST \
--url https://api-partner.houdiniswap.com/v2/exchanges/multi/recovery \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"multiId": "<string>"
}
'import requests
url = "https://api-partner.houdiniswap.com/v2/exchanges/multi/recovery"
payload = { "multiId": "<string>" }
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({multiId: '<string>'})
};
fetch('https://api-partner.houdiniswap.com/v2/exchanges/multi/recovery', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-partner.houdiniswap.com/v2/exchanges/multi/recovery",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'multiId' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api-partner.houdiniswap.com/v2/exchanges/multi/recovery"
payload := strings.NewReader("{\n \"multiId\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api-partner.houdiniswap.com/v2/exchanges/multi/recovery")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"multiId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-partner.houdiniswap.com/v2/exchanges/multi/recovery")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"multiId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"saAddress": "0x3aF1c90b5E2d7B4a8c6E9f0a1B2c3D4e5F607182",
"assets": [
{
"tokenAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7",
"tokenSymbol": "USDT",
"decimals": 6,
"balance": "1000000000",
"sourceHoudiniIds": [
"hxK7mQp2"
]
}
],
"transactions": [
{
"houdiniIds": [
"hxK7mQp2"
],
"txData": {
"userOpHash": "0x7b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f90a",
"to": "0xdac17f958d2ee523a2206206994597c13d831ec7",
"data": "0xa9059cbb000000000000000000000000b7de6b6eebf7401afea5a49d6405c9048fef2d40",
"value": "0",
"chainId": 1,
"tokenAmount": "1000000000"
}
}
]
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"fields": {},
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}{
"message": "<string>",
"code": "<string>",
"requestId": "<string>"
}Authorizations
Send Authorization: <ApiKey>:<ApiSecret> — joined by a colon, raw. No Bearer prefix, no base64.
Body
application/json
Request body for POST /exchanges/multi/recovery
The multi exchange group ID
Maximum string length:
64Response
Recovery data
Smart account holding the stuck funds. It is owned by the wallet that built the batch, so the funds stay recoverable by that wallet alone.
Every stuck token, with its balance.
Show child attributes
Show child attributes
Withdrawal transactions to sign and submit, one per batch.
Show child attributes
Show child attributes