Delete execution
DELETE /executions/{wallet}/{executionId}
DELETE /executions/{wallet}/{executionId}Delete a non-final execution by signing the literal string delete_execution:{executionId} with the wallet that owns it.
TL;DR
Message to sign: the ASCII string
delete_execution:+ the execution ID. No JSON, no envelope, no hashing.Signing op:
signMessage(Solana / NEAR),personal_sign(EVM),signMessageV2(Tron), or TonConnectsignData({type:'text'})(TON).HTTP:
DELETE /api/v1/executions/{walletAddress}/{executionId}, JSON body. Per-chain shape:
Solana
raw_ed25519
signature, publicKey
NEAR
nep413
signature, publicKey, nep413{recipient,nonce}
EVM
erc191
signature
Tron
tip191
signature
TON
ton_connect
signature, publicKey, tonConnect{domain,timestamp,address}
EVM and Tron omit publicKey because both are secp256k1 — the backend recovers the address from the signature via ecrecover. Solana, NEAR, and TON must send it — Ed25519 doesn't let the verifier recover the key from the signature. TON additionally sends a tonConnect envelope (the wallet folds its domain/timestamp/address into the signed digest).
The message
delete_execution:e5abf7ce-1187-4562-b2a7-c52d6560f327Build it client-side from the execution ID — there is no GET to fetch it. The backend rebuilds the same string from the URL path and verifies your signature against it.
Do not wrap in JSON, do not hash, do not prepend any chain envelope. The wallet adds whatever framing its standard requires ("\x19Ethereum Signed Message:", NEP-413 borsh, etc.) — that's the wallet's job.
Solana / raw_ed25519
raw_ed25519Sign the raw bytes of the message with Phantom (or any Solana wallet exposing signMessage).
Three encoding details that matter:
Sign bytes, not a string.
signMessageexpects aUint8Array. Passing the JS string may UTF-8-re-encode in a way that doesn't match what the backend hashes.Signature is base58, not base64. Phantom returns 64 raw bytes (
R‖S). Encode withbs58, then prefix withed25519:.Public key: Phantom returns it in Solana's native base58 via
publicKey.toBase58(). Just prefix withed25519:— no further encoding.
Example submit body:
{walletAddress} in the URL is the base58 Solana account — the same string window.solana.publicKey.toBase58() returns.
NEAR / nep413
nep413Sign a NEP-413 payload with a NEAR wallet (HOT, MyNearWallet, Meteor, etc. — anything exposing signMessage), then also send the nonce and recipient in a top-level nep413 block.
Four encoding details that matter:
Nonce is 32 raw bytes for the wallet, base64 on the wire. The wallet expects 32 bytes; the JSON body carries the same nonce base64-encoded.
Recipient must be exactly
intents.near. It is mixed into the signed digest server-side.Signature re-encoding. Wallets return base64 per NEP-413; the backend verifier wants base58 with
ed25519:.Public key prefix. Wallets disagree about whether to include
ed25519:. Detect and add it if missing — never add it twice.
Example submit body:
Why send nep413.{recipient, nonce} separately?
nep413.{recipient, nonce} separately?They're inside the signed payload — why repeat them on the wire?
Because the backend has to reconstruct the exact bytes the wallet signed in order to verify the signature, and NEP-413 mixes recipient and nonce into those bytes (borsh-encoded with the message, then SHA-256-hashed). The signed payload itself isn't sent as a single blob — the wire format splits it into signature + publicKey + the nep413 fields, and the server reassembles them.
nep413 is therefore mandatory for NEAR. If you omit it the handler returns 400 {"error": "nep413 fields are required for NEAR"}. There is no raw-ed25519 path for NEAR — in practice NEAR wallets don't expose raw byte signing anyway, only signMessage.
{walletAddress} in the URL is either the named account (alice.near) or the 64-char hex implicit account.
TON / ton_connect
ton_connectSign the literal message via TonConnect's signData text payload, then send the signature, the public key, and the wallet-chosen tonConnect envelope.
Four encoding details that matter:
Use
signData(text variant), notsendTransaction. This is an off-chain message signature. The wallet builds the0xffff || "ton-connect/sign-data/" … "txt" …+ SHA-256 digest internally — do not pre-hash, do not wrap.Signature is base64 from the wallet → base58 on the wire. Decode to bytes, assert 64 (
R‖S),bs58-encode, prefixed25519:.publicKeyis from connect time and mandatory. A TON address doesn't contain the key — TonConnect exposesaccount.publicKey(hex);bs58-encode and prefixed25519:. Use a wallet that returns it (e.g. Tonkeeper).The
tonConnectenvelope must be sent. The wallet foldsdomain/timestamp/addressinto the signed digest at signing time, so the backend rebuilds the digest from these wire values plus thedelete_execution:<id>string it reconstructs from the URL.
Example submit body:
publicKey and tonConnect are both required — omit publicKey → 400 {"error": "publicKey is required"}; omit the envelope → 400 {"error": "tonConnect fields are required for TON"}. Unlike the /submit path there's no signer_id or deadline check here — there is no stored intent, just the literal message. See ../ton/ton-signature-verification.md.
{walletAddress} in the URL is the URL-safe non-bounceable account (UQ…); the bounceable (EQ…) and raw (<workchain>:<hex>) forms are also accepted.
EVM / erc191
erc191Sign the message as a UTF-8 string with MetaMask personal_sign (or any EVM wallet exposing the EIP-191 / personal_sign RPC).
Three encoding details that matter:
Argument order:
[message, address].vnormalization: only byte 64 of the 65-byte signature is touched (27 → 0,28 → 1). Do not editrors. Do not re-add27later.bs58, not base64: the backend expects base58 with the
secp256k1:prefix.
Example submit body:
No publicKey. The backend runs ecrecover on "delete_execution:" + executionId and the signature, then compares the recovered address to {walletAddress} in the URL (case-tolerant).
Tron / tip191
tip191Sign the literal message with TronLink signMessageV2 (TIP-191) — the Tron analog of personal_sign. Tron is the secp256k1 twin of EVM: same wire shape as erc191, only the standard label and wallet prefix differ.
Three encoding details that matter:
Use
signMessageV2, not the legacysign/signMessage. Only V2 implements TIP-191 (the\x19TRON Signed Message:\nprefix the backend verifies against); the older calls use a different, incompatible scheme.vnormalization: only byte 64 of the 65-byte signature is touched (27 → 0,28 → 1). Do not editrors. Do not re-add27later. Identical to the ERC-191 path.bs58, not base64: the backend expects base58 with the
secp256k1:prefix.
Example submit body:
No publicKey. Like EVM, the backend recovers the secp256k1 signer from "delete_execution:" + executionId and the signature, then parses the wallet's base58 T… address to its embedded 20-byte account and compares — that account is the same 20 bytes an EVM address carries.
HTTP shape
The body is sent in the request body. With axios.delete specifically, that means the data: option — not the second positional argument:
{walletAddress} format per chain:
Solana: base58 (e.g.
7XSfQk…)NEAR: named account (
alice.near) or 64-char hex implicitEVM:
0x…(40 hex chars, case-tolerant)Tron: base58
T…(e.g.TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t)TON: URL-safe non-bounceable user-friendly address (
UQ…);EQ…and raw<workchain>:<hex>also accepted
Preconditions and responses
Deletable statuses: CREATED, DEPOSIT_PENDING, OPERATION_PENDING, EXPIRED, DEPOSIT_FAILED, OPERATION_FAILED.
SUCCESS is not deletable — successful swaps stay in the user's history.
Response codes
200
Deleted
{"result": {"status": "DELETED"}}
400
Bad signature, missing field, unsupported chain
{"error": "..."}
404
Execution not found for this wallet
{"error": "..."}
409
Execution is in a non-deletable status
{"error": "..."}
Last updated
