Authenticated transactions¶
By default, Photon broadcasts your transaction from a shared relayer address. On-chain, msg.sender is a pooled identity — and because relaying is region-routed, that address can even differ from one request to the next. Most sponsored calls don't care. But some contracts do: allowlists keyed on the caller, per-user on-chain identity, or any flow where the sender address must be predictable.
Authenticated transactions solve this. When you set isAuthenticatedTx and provide a derivationPath, Photon executes the transaction from a key derived for that path instead of the shared relayer key. The derivation is deterministic: the same path always produces the same key, so the same sender address — every time, on every submission.
How it works¶
You add two fields to a normal submit request:
| Field | Type | Description |
|---|---|---|
isAuthenticatedTx |
boolean | Set true to execute from a derived key instead of the shared relayer. Defaults to false. |
derivationPath |
string | Selects which key to derive. Same path, same sender address; different paths, different addresses. |
transactionType |
string | Optionally set to "authenticated" to tag the transaction record. One of flash, flash-blocks, authenticated, funding-signed. |
Everything else about the transaction lifecycle is unchanged — validation, retries, status tracking, and costUSD accounting on the transaction record all behave exactly as they do for a standard relay. Only the signing identity differs.
Use case: stable per-user sender addresses¶
Assign each of your users their own derivation path. Every transaction you submit for that user then lands on-chain from that user's dedicated address:
- Contracts can allowlist the address once and rely on it permanently.
- On-chain activity is cleanly attributable per user without you managing any keys.
- The address never changes, regardless of which region relays the transaction.
Info
Treat the derivation path as a stable identifier — store it alongside your user record and never rotate it, or the sender address will change with it.
Usage¶
Requests are authenticated with your api-key header — see Get API access.
curl -X POST https://photon.example.com/api/submit-tx \
-H "Content-Type: application/json" \
-H "api-key: YOUR_API_KEY" \
-d @- <<'JSON'
{
"to": "0x3dbE34f2C21b3B2980d4dc53f3c7E51e39663F49",
"callData": "0xa9059cbb...",
"chainId": 8453,
"isAuthenticatedTx": true,
"derivationPath": "m/44'/60'/0'/0/42",
"transactionType": "authenticated",
"label": "user-42 transfer"
}
JSON
const res = await fetch("https://photon.example.com/api/submit-tx", {
method: "POST",
headers: {
"Content-Type": "application/json",
"api-key": process.env.EDITH_API_KEY!,
},
body: JSON.stringify({
to: "0x3dbE34f2C21b3B2980d4dc53f3c7E51e39663F49",
callData: "0xa9059cbb...",
chainId: 8453,
isAuthenticatedTx: true,
derivationPath: "m/44'/60'/0'/0/42",
transactionType: "authenticated",
label: "user-42 transfer",
}),
});
const body = await res.json();
A successful submission returns 201:
{
"success": true,
"data": {
"txId": "68fa3450539a3c9d28bbca33",
"estimatedCostUSD": 0.42
},
"timestamp": "2026-07-29T09:12:44.120Z"
}
Track it like any other transaction with Get transaction status, or submit with Submit and wait to receive the full record in one call.
Next¶
- Submit a transaction — full request schema
- Region routing — why the shared relayer address varies
- EIP-7702 authorizations — another way to control the executing identity