Relay an EVM transaction¶
This guide walks through submitting a gas-sponsored EVM transaction, choosing between async and sync submission, and checking its status.
Prerequisites
- An API key — Get API access
- The target contract address and ABI-encoded call data
1. Build the request body¶
POST https://photon.example.com/api/submit-tx accepts:
| Field | Type | Required | Notes |
|---|---|---|---|
to |
string | yes | Recipient or contract address. |
callData |
string | yes | Hex-encoded call data; "0x" for a plain transfer. |
chainId |
number | yes | Target chain. See Supported networks. |
value |
string | no | Native value in wei, as a base-10 integer string. Default "0". |
gasPrice |
string | no | Legacy gas price in wei. |
maxFeePerGas |
string | no | EIP-1559 max fee in wei. |
maxPriorityFeePerGas |
string | no | EIP-1559 priority fee in wei. |
gasLimit |
string | no | Gas limit override. |
maxUSD |
number | no | Cost ceiling in USD, enforced when the transaction is picked up for relaying. |
label |
string | no | Free-form tag echoed back in status lookups. |
retries |
number | no | Retry budget for transient relay failures. Default 0. |
Gas override rules — violations return error code TRANSACTION_005:
- Omit all gas fields to let Photon price the transaction.
- Legacy mode:
gasPricealone. EIP-1559 mode:maxFeePerGasandmaxPriorityFeePerGas, always together. gasPricecannot be combined with either EIP-1559 field.- Every gas field (including
gasLimit) must be a base-10 integer string.
2. Submit asynchronously¶
const res = await fetch("https://photon.example.com/api/submit-tx", {
method: "POST",
headers: { "api-key": "YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
to: "0x3dbE34f2C21b3B2980d4dc53f3c7E51e39663F49",
callData: "0x",
chainId: 84532,
value: "1000000000000000",
maxUSD: 0.5,
label: "payout-42",
}),
});
const { data } = await res.json();
console.log(data.txId);
A 201 response returns the transaction id:
{
"success": true,
"data": {
"txId": "68fa3450539a3c9d28bbca33",
"estimatedCostUSD": 0.0021
},
"timestamp": "2026-07-29T10:15:00.000Z"
}
3. Or submit synchronously¶
POST https://photon.example.com/api/submit-tx-sync wraps the same body in tx and waits for the result:
{
"tx": { "to": "0x3dbE34f2C21b3B2980d4dc53f3c7E51e39663F49", "callData": "0x", "chainId": 84532, "value": "1000000000000000" },
"timeoutMs": 30000,
"includeReceipt": true,
"includeRevertInfo": true,
"returnOnTxHash": false
}
timeoutMsmust be between1000and120000(default30000); values outside the range returnVALIDATION_004.returnOnTxHash: truereturns as soon as a transaction hash exists instead of waiting for a terminal status.- A
200response carries the full transaction record. If the timeout elapses first, you get a202and the record includes"timedOut": true— the transaction keeps processing, so poll its status.
4. Check status¶
GET https://photon.example.com/api/tx?id=<txId> returns the record inside the standard envelope. status is one of NOT_PICKED_UP, PENDING, EXECUTED, FAILED, or NEEDS_TO_BE_RETRIED.
curl "https://photon.example.com/api/tx?id=68fa3450539a3c9d28bbca33&includeReceipt=true&includeRevertInfo=true"
Warning
includeReceipt and includeRevertInfo are query-string flags: only the strings true or 1 enable them. They add receipt and revert objects to the record when available.
Unknown transaction ids return a 404 error envelope with code TRANSACTION_003.
Related¶
- Submit a transaction · Submit and wait · Get transaction status
- Estimate transaction cost before submitting
- Error codes