Skip to content

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