Skip to main content
Relay an existing Safe transaction through Rhinestone’s native Safe endpoint. This flow submits owner-signed execTransaction calldata directly; it does not create or submit a Rhinestone SDK intent.

Construct and sign the Safe transaction

A sponsored relay requires all five Safe gas-refund fields to be zero. The Safe can still send native value in its inner call: value comes from the Safe’s balance, not from the relayer or sponsorship budget.
Build against the Safe’s current onchain nonce. The API recomputes safeTxHash from the encoded transaction at that nonce and rejects a stale nonce, mismatched hash, invalid signatures, or an unsupported Safe proxy.
Anyone who obtains the fully signed calldata can submit it. Treat it as an executable transaction until the Safe nonce changes.
Standard ECDSA signatures and correctly encoded EIP-1271 contract signatures are compatible. A v = 1 pre-validated signature does not work merely because its signer is a Safe owner: the Safe sees SafeRelayExecutor as msg.sender, not that owner. It works only after that owner calls approveHash(safeTxHash) onchain.

Relay the transaction

Send the Safe address as to, the complete execTransaction calldata as data, and the exact hash the owners signed:
A successful submission returns HTTP 201 and { taskId }. The taskId is a decimal string and identifies this exact Safe transaction. Resubmitting the same transaction is idempotent and returns the same task, including after a terminal outcome. The submitted chainId comes from RPC_URL, preventing the example from signing on one network and relaying on another.

Observe success or failure

Poll the status route until it returns a terminal code:
Submission acceptance is not execution success. Persist taskId, poll through temporary network failures, and treat only 200 as successful. A terminal task is not revived by resubmission; construct and sign a new Safe transaction for a genuine retry.

Sponsorship and Safe-paid gas

The end-to-end example requests sponsorship by signing all gas-refund fields as zero. On mainnets, the sponsorship budget covers the estimated wrapped relay gas plus any applicable relay fee. It does not fund the Safe’s inner native value, token transfers, or contract calls. Complete Sponsorship setup and fund its budget before submitting. A request without available sponsorship is rejected rather than silently changed to Safe-paid gas. Safe-paid gas is supported for a single execTransaction, but it requires a complete Safe fee-preview integration before you collect signatures. Fetch GET /relay/gas-price?chainId=<chainId> with Intents: Read access immediately before the preview, and use the returned gasPriceWei unchanged as the transaction’s signed gasPrice. Reject the quote after validUntil. The gas-price endpoint is an input to fee calculation, not a fee estimator. Your preview integration must calculate safeTxGas and baseGas for the complete Rhinestone relay path, including the SafeRelayExecutor wrapper overhead. A direct Safe estimate or Protocol Kit’s defaults do not include that wrapper overhead and can underfund the relayer. Sign the complete preview output with the native zero address as gasToken and refundReceiver, and fund the Safe for the maximum signed refund plus any inner native transfer. If your integration cannot account for the wrapper overhead, use the sponsored flow above. Safe-paid submissions do not consume the project’s sponsorship budget. Batches and Safe deployments are sponsored-only.

Submission failures

The endpoint also accepts canonical Safe deployment, passkey-signer deployment, and MultiSendCallOnly payloads under stricter rules. This guide uses the supported single-transaction path; do not send arbitrary calldata or a generic SDK intent payload to /safe-transactions.