curl --request POST \
--url https://api.beta.getpara.com/v1/wallets/{walletId}/transactions/{transactionId}/cancel \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--header 'X-API-Key: <api-key>' \
--data '
{
"maxExecutionFeeWei": "1000000000000000"
}
'import requests
url = "https://api.beta.getpara.com/v1/wallets/{walletId}/transactions/{transactionId}/cancel"
payload = { "maxExecutionFeeWei": "1000000000000000" }
headers = {
"Idempotency-Key": "<idempotency-key>",
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
'X-API-Key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({maxExecutionFeeWei: '1000000000000000'})
};
fetch('https://api.beta.getpara.com/v1/wallets/{walletId}/transactions/{transactionId}/cancel', 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.beta.getpara.com/v1/wallets/{walletId}/transactions/{transactionId}/cancel",
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([
'maxExecutionFeeWei' => '1000000000000000'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>",
"X-API-Key: <api-key>"
],
]);
$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.beta.getpara.com/v1/wallets/{walletId}/transactions/{transactionId}/cancel"
payload := strings.NewReader("{\n \"maxExecutionFeeWei\": \"1000000000000000\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("X-API-Key", "<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.beta.getpara.com/v1/wallets/{walletId}/transactions/{transactionId}/cancel")
.header("Idempotency-Key", "<idempotency-key>")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"maxExecutionFeeWei\": \"1000000000000000\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.beta.getpara.com/v1/wallets/{walletId}/transactions/{transactionId}/cancel")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"maxExecutionFeeWei\": \"1000000000000000\"\n}"
response = http.request(request)
puts response.read_body{
"transactionId": "550e8400-e29b-41d4-a716-446655440000",
"walletId": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"walletType": "EVM",
"intentKind": "transfer",
"status": "submitted",
"createdAt": "2026-10-14T12:00:00Z",
"manualRecovery": {
"action": "cancel",
"state": "active",
"nonce": 7,
"originalHash": "0x1234abcd...",
"attempt": {
"stage": "prepared",
"preparedAt": "2026-10-14T12:05:00Z"
}
}
}{
"code": "INVALID_REQUEST",
"message": "<string>",
"transactionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"failureStage": "mpc_sign",
"failureCode": "<string>",
"signedTransaction": "<string>"
}{
"code": "UNAUTHORIZED",
"message": "secret api key not provided"
}{
"code": "FORBIDDEN",
"message": "invalid secret api key"
}{
"code": "NOT_FOUND",
"message": "wallet not found"
}{
"code": "INVALID_REQUEST",
"message": "<string>",
"transactionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"failureStage": "mpc_sign",
"failureCode": "<string>",
"signedTransaction": "<string>"
}{
"code": "RATE_LIMITED",
"message": "Rate limit exceeded, try again shortly."
}{
"code": "INTERNAL_ERROR",
"message": "Internal Server Error"
}{
"code": "INVALID_REQUEST",
"message": "<string>",
"transactionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"failureStage": "mpc_sign",
"failureCode": "<string>",
"signedTransaction": "<string>"
}Cancel Transfer
Request cancellation of an existing unresolved transfer using a zero-value native transfer
to the same wallet, with empty calldata and gas limit 21000. It retains the original nonce,
chain, and type 0 or type 2 transaction family. The wallet must have no deployed or delegated
code (eth_getCode returns 0x), otherwise admission returns 400 RECOVERY_CANCEL_UNSUPPORTED.
A verified successful cancellation marks the original record failed with failureCode: CANCELLED
only after its canonical receipt and finality are verified.
Requires a secret API key, current authority over an API-created, unclaimed wallet,
and a verified pending original hash, sender, nonce, payment envelope, and fees.
Supports ordinary self-funded EVM native or ERC-20 /transfer records outside
automatic retry, sponsorship, yield, and arbitrary sign-transaction broadcasts.
Older records without spend-accounting metadata require a current policy with no spend limits.
Historical failed/broadcast or failed/monitor_timeout records can qualify only when the
original is verified as still pending. A receipt or advanced latest sender nonce rejects recovery.
Supply one positive uint256 maxExecutionFeeWei integer string. Para chooses fees from
current network estimates with at least a 12.5% increase in every original fee component,
rounded up; a zero component must become at least 1. The replacement’s gas limit times
gasPrice (type 0) or maxFeePerGas (type 2) stays within your ceiling. Separate chain fees,
such as L1 data fees, are excluded. The wallet must cover the replacement’s value and selected gas fees.
If the minimum fee bump exceeds the ceiling, admission returns 400 RECOVERY_FEE_CAP_REACHED.
400 RECOVERY_FEES_ABOVE_BUDGET means the current base-fee floor plus the minimum required tip
cannot fit (the base-fee floor alone for type 0). Neither error admits an operation; retry with a
higher ceiling and a new Idempotency-Key. Higher recommendations are capped when the required minimum fits.
Save a new Idempotency-Key with this body. Selected fees are saved once; replays retrieve
the same operation without choosing new fees or signing again. Only one manual operation is
accepted across speed-up and cancellation for each original transfer. Current authority and
policy are checked before signing. Para does not bump the selected fees automatically.
Signing authorization expires five minutes after acceptance without cancelling signed transactions.
Recovery normally becomes stopped after the single replacement is submitted, with reason
RECOVERY_MANUAL_ATTEMPT_COMPLETE. Chain reconciliation continues; keep polling status and monitoring.
Only if you choose to abandon an unresolved payment, use the existing fresh sign-transaction
cancellation flow. This grant cannot renew or resume. See Cancel a stopped payment.
202 returns the original transaction record with manualRecovery metadata. Poll its existing
lookup endpoint. The original and replacement compete for the same nonce; either can win.
The original hash stays unchanged; monitoring.winningHash identifies the verified winner.
curl --request POST \
--url https://api.beta.getpara.com/v1/wallets/{walletId}/transactions/{transactionId}/cancel \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--header 'X-API-Key: <api-key>' \
--data '
{
"maxExecutionFeeWei": "1000000000000000"
}
'import requests
url = "https://api.beta.getpara.com/v1/wallets/{walletId}/transactions/{transactionId}/cancel"
payload = { "maxExecutionFeeWei": "1000000000000000" }
headers = {
"Idempotency-Key": "<idempotency-key>",
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
'X-API-Key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({maxExecutionFeeWei: '1000000000000000'})
};
fetch('https://api.beta.getpara.com/v1/wallets/{walletId}/transactions/{transactionId}/cancel', 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.beta.getpara.com/v1/wallets/{walletId}/transactions/{transactionId}/cancel",
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([
'maxExecutionFeeWei' => '1000000000000000'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>",
"X-API-Key: <api-key>"
],
]);
$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.beta.getpara.com/v1/wallets/{walletId}/transactions/{transactionId}/cancel"
payload := strings.NewReader("{\n \"maxExecutionFeeWei\": \"1000000000000000\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("X-API-Key", "<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.beta.getpara.com/v1/wallets/{walletId}/transactions/{transactionId}/cancel")
.header("Idempotency-Key", "<idempotency-key>")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"maxExecutionFeeWei\": \"1000000000000000\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.beta.getpara.com/v1/wallets/{walletId}/transactions/{transactionId}/cancel")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"maxExecutionFeeWei\": \"1000000000000000\"\n}"
response = http.request(request)
puts response.read_body{
"transactionId": "550e8400-e29b-41d4-a716-446655440000",
"walletId": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"walletType": "EVM",
"intentKind": "transfer",
"status": "submitted",
"createdAt": "2026-10-14T12:00:00Z",
"manualRecovery": {
"action": "cancel",
"state": "active",
"nonce": 7,
"originalHash": "0x1234abcd...",
"attempt": {
"stage": "prepared",
"preparedAt": "2026-10-14T12:05:00Z"
}
}
}{
"code": "INVALID_REQUEST",
"message": "<string>",
"transactionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"failureStage": "mpc_sign",
"failureCode": "<string>",
"signedTransaction": "<string>"
}{
"code": "UNAUTHORIZED",
"message": "secret api key not provided"
}{
"code": "FORBIDDEN",
"message": "invalid secret api key"
}{
"code": "NOT_FOUND",
"message": "wallet not found"
}{
"code": "INVALID_REQUEST",
"message": "<string>",
"transactionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"failureStage": "mpc_sign",
"failureCode": "<string>",
"signedTransaction": "<string>"
}{
"code": "RATE_LIMITED",
"message": "Rate limit exceeded, try again shortly."
}{
"code": "INTERNAL_ERROR",
"message": "Internal Server Error"
}{
"code": "INVALID_REQUEST",
"message": "<string>",
"transactionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"failureStage": "mpc_sign",
"failureCode": "<string>",
"signedTransaction": "<string>"
}Authorizations
Your partner secret key (server-side only)
Headers
UUID for request tracing. Para returns one if omitted.
Save a new key for this manual recovery intent and reuse it with the same body for HTTP retries.
1 - 256Path Parameters
Wallet UUID. A malformed or inaccessible wallet ID returns 404.
"0a1b2c3d-4e5f-6789-abcd-ef0123456789"
Original persisted /transfer transaction ID.
Body
Positive uint256 execution-gas fee ceiling for this replacement in native-token base units. Bounds gasLimit times gasPrice (type 0) or maxFeePerGas (type 2), excluding separate chain fees such as L1 data fees. Para selects and saves the replacement fees once, within this ceiling.
^[0-9]{1,78}$"1000000000000000"
Response
Manual recovery accepted or replayed; poll the original transaction for its outcome.
"550e8400-e29b-41d4-a716-446655440000"
EVM, SOLANA REST operation that created the record.
transfer, sign_transaction, yield pending and submitted are nonterminal. confirmed and reverted are verified
chain outcomes. failed can report a signing or broadcast error, or a verified same-nonce winner;
historical broadcast and monitoring-timeout errors can retain an uncertain chain outcome.
Treat unknown future values as nonterminal.
For sponsored operations, inclusion is submitted with stage included until
receipt verification. Successful execution with verified token delivery is confirmed;
an included execution revert is reverted. Unknown submission stays nonterminal,
and unresolved token evidence remains pending with stage delivery_unverified.
Legacy EVM transfer and sign_transaction broadcasts remain submitted during durable
reconciliation after the 30-minute active window. Receipt resolution requires canonical
block identity, at least two confirmations, and finalized-block evidence. Timeout, RPC errors,
and nonce consumption without an identified winner are unresolved, not payment failure.
Solana broadcasts require finalized signature status and also retain unresolved monitoring context.
A verified Para automatic-retry or manual speed-up variant resolves the same payment as confirmed or reverted.
A verified cancellation or unrelated identified same-nonce winner leaves the original failed with REPLACED or CANCELLED;
inspect monitoring for the actual winner's outcome. Historical failed / monitor_timeout
records remain uncertain until chain-backed reconciliation corrects them. Historical failed/broadcast
records can also be eligible for manual recovery when the original is verified as still pending.
pending, submitted, confirmed, reverted, failed Present in manual-recovery POST/replay and single-transaction GET responses. Not included in transaction-list summaries. State tracks recovery processing; use the parent status and monitoring to establish the payment or cancellation outcome.
Show child attributes
Show child attributes
Sponsored records use sponsored; legacy responses may omit this field.
legacy, sponsored EVM chain ID (EVM records only).
Solana network (Solana records only).
SOLANA, SOLANA_DEVNET Destination address. Absent for Solana sign_transaction records because Para does not decode arbitrary Solana instructions.
Transfer amount in smallest unit (wei / lamports / token smallest unit), or EVM sign_transaction value when supplied.
Token contract (ERC-20 / SPL mint) address if a token transfer, else absent. Always absent for sign_transaction records.
Optional durable monitoring metadata for legacy EVM and Solana broadcasts. Active monitoring hands off after 30 minutes without changing unresolved chain outcome to failed. After 24 hours, escalation retains unresolved state. Healthy pending checks stay at most five minutes apart during the first 24 hours, then may back off to one hour. RPC errors and missing context use backoff capped at one hour. After observing receipt or signature evidence, checks for finality, confirmations, or canonical chain evidence run every 60 seconds regardless of age. Unsupported finality evidence or missing legacy context remains unresolved and requires operational follow-up.
Show child attributes
Show child attributes
Original transaction hash. Null or absent before signing; an identified same-nonce winner is exposed separately in monitoring.winningHash. Sponsored operations expose this after inclusion; never a UserOperation hash.
Block number as a decimal string (present when confirmed or reverted).
Stage at which the pipeline failed. monitor_timeout appears only on historical records and does not establish chain failure.
mpc_sign, signature_apply, signer_verify, broadcast, monitor_timeout Structured broadcast error code, or REPLACED / CANCELLED when a verified same-nonce winner superseded the original transaction.
Truncated error message (max 512 chars).
Set when status first moves to submitted.
Set when status reaches a terminal value (confirmed, reverted, failed).