Skip to main content
An Agent Checkout form can contain ordinary and protected fields. Render ordinary fields with your own controls. Render each field whose handling is "protected" with CrossmintProtectedInput; your application receives a reference instead of its value.

Prerequisites

  • Checkout integration: Complete the Agent Checkouts quickstart.
  • React SDK: Install @crossmint/client-sdk-react-ui version 4.9.0 or later.
  • API key: Use a production key with agent-checkouts.read and agent-checkouts.update. Add protected-inputs.create to the client-side key when collecting protected fields.
  • User authentication: Pass the buyer’s JWT from your external authentication integration. Use the same project, environment, and user as the checkout run.

Collect and Submit Answers

1

Read the requested fields

Use an open input_request part from the Messages API, or requiredAction.request when polling the run. Both expose the same interaction.fields descriptors. A protected field belongs to a "form" interaction.
Pass each protected descriptor unchanged as the component’s field. It supplies the key, accessible label, requiredness, and supported input hints. display: "masked" controls appearance; handling: "protected" controls how the value is collected. A standard text field can also be masked.
2

Render ordinary fields with your controls

Keep the request’s field order and use each key as its answer key. Display its label, respect required, and pass supported presentation hints to your controls. For a standard single-line text descriptor:
StandardTextField.jsx
Your parent component owns the value and onChange callback. For other input kinds, choose a control and submit the corresponding typed value:Use choice labels for display and values for answers. Placeholder options are not answers. Disabled options cannot be newly selected; preserve already-selected disabled options. Browser form serialization omits disabled controls, so include those locked selections explicitly when constructing answers.For example, an ordinary response can contain email: "buyer@example.com", quantity: 2, giftWrap: false, and colors: ["navy", "black"]. Submit only keys requested by this form. Omit unanswered optional keys; null is not an answer.
3

Render and collect protected fields

This example handles one protected field. Your page owns the visible label, button, and error text. The iframe contains only the input. Call ref.collect() when the buyer chooses to continue; an HTML <form> is optional.
ProtectedField.tsx
Pass your client-side API key as apiKey, the buyer’s JWT as jwt, and the descriptor from interaction.fields as field. Mount this request’s UI with key={requestId} so a replacement request resets its state. If your page already has a CrossmintProvider, use that provider instead of nesting another one. External authentication does not require CrossmintAuthProvider.For a form with multiple protected fields, the parent owns one Continue button and one ref per field. Collect them together with Promise.all, then submit the combined answers. Check every result before submitting. Each result is independent: correcting one field does not discard an unchanged field’s successful reference.collect() validates and registers the value before returning a reference. Numeric parsing runs during collection, so invalid numeric text is reported before you submit an answer. Unchanged successful collections reuse their reference until it expires; editing or clearing the field invalidates that reuse.
4

Submit the complete form answer

Combine the collected reference with ordinary answers under the keys from the request. For the email and password example, send this body to POST /api/unstable/agent-checkouts/{runId}/messages:
Send all required answers in one response.answers object, using the field keys from the request. Ordinary answers are strings, booleans, numbers, or choice values; protected answers are { protectedInputId }. Answers do not repeat handling. Omit unanswered optional field keys.Follow response and retry handling: retain one message ID and body until acknowledged, and use a new ID after correcting a definitive validation rejection. If the request closes or expires, load the current request.An accepted answer resumes the run; it does not confirm that the merchant accepted the value. Follow subsequent messages for application results or another request.

Choose the Input Type and Presentation

Use appearance to supply fonts and supported theme variables for the input. Style labels, buttons, and error messages in your own page. disabled and invalid update the mounted input dynamically. Numeric fields use numeric keyboard hints; a text code can specify inputMode: "numeric" without losing leading zeros. Protected references last 24 hours by default and at most 7 days. The component’s optional expiresAt sets the reference lifetime; the request’s expiresAt is the separate deadline to answer the request.

Use a Chat or Native Handoff

A messaging agent can collect ordinary answers, then send the buyer to an authenticated page that renders only the protected fields. Your application associates that page with the run and request, merges the references with the ordinary answers, and submits the complete response. A native app can use the same page in a webview. Collection keeps plaintext out of your application JavaScript and answer messages. After application to a merchant page, page content, screenshots, or recordings can expose values. Do not rely on the collection component to mask browser evidence.

Next Steps

Reuse Merchant Sessions

Reuse the buyer’s merchant session on later checkouts

Send a Message

Review form, payment, and steering message formats