← Solana Builder

Intermediate · LESSON 11 OF 12

11. Share safe Solana transactions with Actions and Blinks

By the end, you can design and audit a solana action api and blink transaction flow without confusing public input, previews, wallet approval, and finalized execution.

Look up Solana terms in the glossary

In this lesson9 field notes · practice · sources · checkpoint
Solana Actions move from public endpoint discovery through server validation, transaction inspection and wallet approval to signature reconciliation; a Blink presents the flow but does not authorize it.
Solana Actions move from public endpoint discovery through server validation, transaction inspection and wallet approval to signature reconciliation; a Blink presents the flow but does not authorize it.Open full-size visual ↗
Read a text version of this diagram

A compatible client performs OPTIONS and GET against a public HTTPS Action endpoint, then displays the action choices. After the person chooses, the client POSTs caller input such as a public key to the endpoint. The server validates all input against canonical application state and returns a transaction proposal. The client decodes and inspects the exact transaction, including required signers, programs, resolved accounts, fee payer, amounts, and freshness. The learner reviews and approves in a wallet. Only then is the transaction submitted and its exact signature reconciled with finalized cluster state before one idempotent fulfillment. Dashed arrows represent untrusted data or proposals; they do not prove identity, approval, submission, or success.

  1. REQUEST + OPTIONS / GET
  2. VALIDATE INPUT + BUILD
  3. REVIEW SIGNERS + COST
  4. REJECT OR APPROVE IN WALLET
FIELD NOTE 01

Separate the Action API from the Blink client

A Solana Action is a publicly reachable API that describes an available wallet action and, after an explicit request, returns a signable transaction or message. A Blink is a client that discovers that API and builds an interface around it. A URL is only a way to locate a request; it does not contain a trusted transaction or grant permission. The wallet still mediates the final signature. Keep this distinction clear in diagrams, logs, and user copy: endpoint metadata is a proposal, a Blink is a presentation client, and the signed transaction is the user-authorized instruction set. A supporting wallet or social client can still choose which Actions it displays.

FIELD NOTE 02

Trace the GET to POST lifecycle

A client first sends GET to learn the title, icon, description, labels, available links, and whether an action is currently disabled. After the person chooses an action, the client sends POST with the account public key and any declared input. The POST response carries a base64 serialized transaction, an optional plain-language message, and optionally a next-action link. The wallet reviews and signs; the client then submits or otherwise executes the approved action and tracks its result. A successful GET proves only that a server responded. A POST account field is caller-supplied input, not a proof that the key signed, owns anything, or consented to a business operation. Treat each response and input as untrusted until independently checked.

FIELD NOTE 03

Implement the protocol surface deliberately

Support the specification’s OPTIONS preflight and JSON GET and POST shapes. Return preflight methods that satisfy the documented Actions requirements, including GET, POST, PUT, and OPTIONS, without confusing an allowed method with a business endpoint you do not implement. Publish an actions.json file at the website root if ordinary website URLs should map to API endpoints, and test the exact path rules rather than assuming a wildcard has the desired scope. The Actions reference specifies Cross-Origin headers for endpoint calls and actions.json; CORS permits browser requests but does not authenticate clients, prevent non-browser callers, or protect a transaction. Since these endpoints are public, avoid cookie-based assumptions and do not place secrets or private account data in response metadata. Return a useful protocol-shaped error when the action is unavailable; expose disabled state when a client can still present the reason safely.

FIELD NOTE 04

Build against validated intent, not arbitrary input

Parse the supplied account as a canonical public key, bound every number and string, reject malformed or unexpected parameters, and derive the intended program accounts from trusted application state. Never trust a label, UI field, referer header, or public-key string to prove identity or authorization. If the action depends on a quote, order, proposal, or limited resource, fetch the canonical record server-side, check its owner and state, and bind its identifier, amount, cluster, and expiry into the transaction. Put an expiry or freshness rule on reusable requests, and define idempotency so repeated POSTs cannot fulfill the same order twice.

FIELD NOTE 05

Review partially signed transactions correctly

An Action response can be unsigned or partially signed. The current specification tells clients not to rely on a fee payer or recent blockhash supplied in an unsigned transaction: set them from the requesting account and a fresh blockhash before signing. If the transaction is partially signed, changing either field invalidates prior signatures. Instead verify every existing signature and reject malformed signatures. The client should sign only with the requested account, only when its signature is required; reject a transaction that requires an unexpected signer. On both paths, decode and inspect programs, account keys, writable accounts, transfer amounts, token mint and program, address-table loaded keys when applicable, and the actual designated fee payer. Simulate when the exact transaction supports it, then show network fee and separate account funding before opening the wallet. A signature is approval of those bytes, not proof that they succeeded.

FIELD NOTE 06

Keep the user in control through confirmation

Show the action domain and a plain-language description, then let the wallet present the transaction details. Explain which wallet pays the network fee; if the fee payer is the learner, the learner pays it, even when the Action itself is free to use. Account creation, rent-exempt storage, protocol fees, and transferred value can debit different accounts and must be described separately. A sponsor is possible only when the transaction and all required signatures are designed for sponsorship; do not imply that an Action automatically makes a transaction sponsored. After submission, reconcile the exact signature against the intended cluster, finality, error, and resulting account state. A timeout is unknown until checked; never fulfill twice or claim success from the POST response alone.

FIELD NOTE 07

Treat links and previews as a security boundary

Action links can be opened in many contexts, so provide an ordinary website fallback for clients that do not support Blinks and never imply every wallet or social platform will unfurl the link. Encode Action URLs according to the scheme, especially when they contain query parameters. Keep sensitive values out of shareable URLs and previews because links can be copied, logged, indexed, or shown to bystanders. Make the destination domain visible, protect APIs from request floods, set bounded response sizes and timeouts, avoid reflecting arbitrary input into markup, and separate public response data from authenticated account records. Registration in a third-party registry is not universal trust or a replacement for local transaction review.

FIELD NOTE 08

Test the API and the bytes independently

Use specification types and the official Actions references for the exact request and response contract, then validate the resulting serialized transaction with Solana libraries. Test OPTIONS from an unrelated origin, GET metadata and unavailable states, each accepted POST input, malformed keys, huge values, replayed orders, stale quotes, unsupported clusters, and structured 4xx/5xx responses. For transaction construction, decode both legacy and supported versioned forms; verify signer requirements and signatures; reject unexpected instructions, programs, destinations, authorities, or fee payers; and test address lookup table resolution when used. A successful local simulation is not a wallet signature, submission, finalized state, production-provider guarantee, or security audit. Use the official Blink Inspector as one protocol debugging aid, not as a security certification.

FIELD NOTE 09

Ship with explicit operational evidence

Pin the Actions SDK and transaction libraries together with their lockfile, keep RPC credentials and signing keys server-side, and deploy HTTPS endpoints with bounded rate limits and monitored error classes. Record safe action IDs, cluster, transaction signature, and final outcome; do not log wallet messages, email, or private business data without a clear need and retention rule. Rehearse degraded RPC, expired blockhashes, duplicate callbacks, RPC timeouts after submission, and rollback before production. Publish an Actions mapping only after CORS, fallback behavior, endpoint ownership, rate limits, response schemas, and wallet previews have been checked on the deployed domain.

MAKE THE CONNECTION

A detail worth keeping.

Specification conformance and application security are separate review tracks. A response can be perfectly shaped JSON and still propose a dangerous destination, an unexpected fee payer, or a replayable business operation. Test schema, origin, and CORS behavior separately from transaction semantics and server-side fulfillment logic.

Work through an example

The Actions specification distinguishes unsigned from partially signed transactions because an existing signature commits to the serialized message. For an unsigned response, the client fills the requested signer account and a fresh blockhash according to the specification. For a partially signed response, verify existing signatures and preserve the message. Do not “fix” bad message fields after a signer has approved them; reject and request a new transaction.

Illustrative public GET metadata only. This is not a transaction and must not be treated as user authorization.
{
  "title": "Course token vote",
  "icon": "https://example.invalid/icon.png",
  "description": "Review a proposed vote before signing.",
  "label": "Choose vote",
  "links": {
    "actions": [
      {
        "label": "Approve",
        "href": "/api/actions/vote?choice=yes",
        "type": "post",
        "parameters": []
      },
      {
        "label": "Reject",
        "href": "/api/actions/vote?choice=no",
        "type": "post",
        "parameters": []
      }
    ]
  }
}

Given a fictional token-voting Action, draw its OPTIONS → GET → POST → wallet review → submit → finalized verification flow. Annotate the domain, caller-controlled inputs, canonical server state, programs, resolved accounts, required signers, fee payer, amount, quote expiry, idempotency key, and retry decision. Mark every fact that still needs proof after an HTTP 200 response.

GUIDED PRACTICE · INTERMEDIATE

Do the work, one step at a time.

Use fictional addresses and disposable test data. Do not enter a recovery phrase or private key. Most exercises work on paper or with a local test; only a lesson that clearly says “read-only Devnet” makes a public network request.

  1. Read the sample GET metadata and identify the visible domain, available action labels, and any missing fallback or disabled state. Treat the server response as untrusted input.
  2. Inspect the declared POST fields. List which values come from the caller and specify the server-side order or proposal record that must be re-read before building a transaction.
  3. For a partially signed response, decode the transaction and list the existing signatures, required signers, fee payer, recent blockhash, programs, and all resolved writable accounts. Reject any signer beyond the requested wallet.
  4. Compare an unsigned response with the same signed sample. State which fields the client must populate for the unsigned case and which fields it must preserve for the partially signed case.
  5. Write a pre-wallet review card that identifies the network, destination program, token mint, raw amount, network fee payer, separate storage funding, quote expiry, and user-facing action.
  6. Simulate the first POST timing out after submission. Define how the server reconciles the exact signature, prevents duplicate fulfillment, reports pending/unavailable states, and authorizes a fresh transaction only when appropriate.

Before you move on, check your reasoning

  • R
  • i
  • s
  • k
  • r
  • e
  • v
  • i
  • e
  • w
  • i
  • s
  • e
  • a
  • s
  • i
  • e
  • r
  • w
  • h
  • e
  • n
  • e
  • a
  • c
  • h
  • l
  • a
  • y
  • e
  • r
  • h
  • a
  • s
  • i
  • t
  • s
  • o
  • w
  • n
  • e
  • v
  • i
  • d
  • e
  • n
  • c
  • e
  • r
  • e
  • c
  • o
  • r
  • d
  • :
  • t
  • h
  • e
  • d
  • o
  • m
  • a
  • i
  • n
  • a
  • n
  • d
  • G
  • E
  • T
  • r
  • e
  • s
  • p
  • o
  • n
  • s
  • e
  • ,
  • v
  • a
  • l
  • i
  • d
  • a
  • t
  • e
  • d
  • s
  • e
  • r
  • v
  • e
  • r
  • -
  • s
  • i
  • d
  • e
  • b
  • u
  • s
  • i
  • n
  • e
  • s
  • s
  • s
  • t
  • a
  • t
  • e
  • ,
  • t
  • h
  • e
  • s
  • e
  • r
  • i
  • a
  • l
  • i
  • z
  • e
  • d
  • t
  • r
  • a
  • n
  • s
  • a
  • c
  • t
  • i
  • o
  • n
  • a
  • n
  • d
  • r
  • e
  • s
  • o
  • l
  • v
  • e
  • d
  • k
  • e
  • y
  • s
  • ,
  • t
  • h
  • e
  • w
  • a
  • l
  • l
  • e
  • t
  • d
  • e
  • c
  • i
  • s
  • i
  • o
  • n
  • ,
  • t
  • h
  • e
  • c
  • l
  • u
  • s
  • t
  • e
  • r
  • -
  • s
  • c
  • o
  • p
  • e
  • d
  • s
  • i
  • g
  • n
  • a
  • t
  • u
  • r
  • e
  • o
  • b
  • s
  • e
  • r
  • v
  • a
  • t
  • i
  • o
  • n
  • ,
  • a
  • n
  • d
  • t
  • h
  • e
  • i
  • d
  • e
  • m
  • p
  • o
  • t
  • e
  • n
  • t
  • f
  • u
  • l
  • f
  • i
  • l
  • l
  • m
  • e
  • n
  • t
  • r
  • e
  • s
  • u
  • l
  • t
  • .
  • I
  • f
  • a
  • n
  • y
  • l
  • a
  • y
  • e
  • r
  • i
  • s
  • u
  • n
  • a
  • v
  • a
  • i
  • l
  • a
  • b
  • l
  • e
  • ,
  • m
  • a
  • r
  • k
  • t
  • h
  • a
  • t
  • s
  • p
  • e
  • c
  • i
  • f
  • i
  • c
  • p
  • r
  • o
  • o
  • f
  • a
  • s
  • u
  • n
  • k
  • n
  • o
  • w
  • n
  • i
  • n
  • s
  • t
  • e
  • a
  • d
  • o
  • f
  • b
  • o
  • r
  • r
  • o
  • w
  • i
  • n
  • g
  • c
  • o
  • n
  • f
  • i
  • d
  • e
  • n
  • c
  • e
  • f
  • r
  • o
  • m
  • a
  • n
  • e
  • i
  • g
  • h
  • b
  • o
  • r
  • i
  • n
  • g
  • l
  • a
  • y
  • e
  • r
  • .

OPEN SELF-CHECK · UNGRADED

Pause and test your reasoning

Practice 1 of 3

A Blink client displays a transaction proposal returned by a public Action API. What does that display prove?

  1. Only that the client rendered a proposal; the wallet must review and authorize the exact transaction.
  2. That the endpoint authenticated the wallet and the chain transaction is finalized.
  3. That the proposal cannot change after the API response.
Reveal the answer and explanation

One best answer: Only that the client rendered a proposal; the wallet must review and authorize the exact transaction.

Presentation is not authentication, authorization, or chain confirmation. Confirm the matching API and transaction behavior against the official Actions protocol reference before building a client.

Sources: Solana Actions and Blinks

Practice 2 of 3

What does the wallet address in an Actions POST body establish by itself?

  1. The address signed the request.
  2. The caller supplied a public key; it is not proof of key control or consent.
  3. The address is always the fee payer.
Reveal the answer and explanation

One best answer: The caller supplied a public key; it is not proof of key control or consent.

Caller-supplied data needs independent validation and cannot establish consent. Confirm the matching API and transaction behavior against the official Actions protocol reference before building a client.

Sources: Solana Actions and Blinks

Practice 3 of 3

The first transaction POST timed out after submission. What is the safe next step?

  1. Assume failure and submit a duplicate transaction.
  2. Mark the business operation complete from the HTTP response.
  3. Reconcile the exact signature and resulting state on the intended cluster before retrying.
Reveal the answer and explanation

One best answer: Reconcile the exact signature and resulting state on the intended cluster before retrying.

A timeout creates uncertainty; exact signature and state reconciliation determine recovery. Confirm the matching API and transaction behavior against the official Actions protocol reference before building a client.

Sources: Solana Actions and Blinks

This practice is not scored, saved, or part of a certificate. Account-based lesson checkpoints and level exams remain separate.

Never enter a recovery phrase or private key into a learning site or lesson exercise.

READ THE SOURCE

Go deeper in the official docs

Reviewed on 2026-10-06. Protocol documentation can change; check the linked page’s current version as you use this material.

  1. Solana Actions and Blinks ↗
  2. Solana Actions specification types ↗
  3. Transactions ↗
  4. Fee Structure ↗

Report an issue with this lesson

YOUR PROGRESS, SAVED

Ready for the checkpoint?

Make a free account to save your progress and unlock the quizzes.

Create free account