Sessions & HITL

Hand a code back to a run that is waiting

Resumes a run parked on a 2FA or approval wall — an SMS or email code, a TOTP, an out-of-band approval, or a credential your own app already holds — on the same parked browser, without restarting.

submit_verification

What it is

The job: Finish a sign-in that got as far as the second factor.

A parked run is a browser that is still open, one field short of being signed in. submit_verification fills that field. Two shapes, matching how the run paused: a PARKED run from run_goal or submit_run gives you a sessionId, and a LIVE streamed run emits an await-user SSE event carrying a token. Pass whichever you were given, plus the code.

An approval you completed out of band — a push notification you tapped on your phone — needs no code at all: resume with just the identifier and the run picks up from the now-cleared wall.

The `secrets` object is the third path and the most easily misused. It exists for the case where a run paused with code: "credential_missing" and YOUR application already holds the credential — a first-party login form, say. The values are merged into the parked session’s vault so the same browser continues without restarting, and they are redacted from every frame, step and log. What it is not for is asking a user to type a password into a conversation with a model; that is what connect_account is for.

Send cancel: true to abandon the wait instead.

The call

Call it exactly like this.

Copied from the tool's registration and the route handler — not paraphrased.

MCPsubmit_verification.mcp.jsonjson
// MCP tool call — server "twin-browser"
{
  "tool": "submit_verification",
  "arguments": {
    "sessionId": "…",
    "code": "482913"
  }
}
POST /api/v1/runs/{id}/resumerequest.shbash
curl -X POST https://twin-browser.com/api/v1/runs/RUN_ID/resume \
  -H "Authorization: Bearer $TWIN_API_KEY" \
  -H "content-type: application/json" \
  -d '{"code":"482913"}'

The two paths are addressed differently. Over REST you resume by the WEB run id — POST /api/v1/runs/{runId}/resume — and the platform looks up the parked engine session from the run record; a texted code on a STREAMED run goes to POST /api/v1/live/resume with its { token, code } instead. The MCP tool takes the engine `sessionId` for the parked path and the SSE `token` for the streamed one.

Parameters accepted by submit_verification
ParameterTypeWhat it does
sessionIdstringThe sessionId from a paused run_goal / submit_run. Resumes the parked engine session directly.
tokenstringThe token from an await-user SSE event on a streamed run. Routed through the web live-resume channel.
codestringThe verification code the user provided. Omit for an approval you completed out of band.
secretsobjectCredentials for a run that paused with credential_missing, e.g. { "email": "…", "password": "…" }. Merged into the parked browser so it continues without restarting; redacted from every frame and log. Only send values your app already holds.
cancelbooleanAbandon the wait or pause instead of submitting a code.

Returns

response.jsonjson
{ "status": "complete", "success": true, "steps": 9, "path": [ … ] }

// …or, if it is still blocked:
{ "status": "paused", "sessionId": "…", "reason": "…" }

What it costs

10 credits on completion

The pause refunded the original run’s reservation in full, so the resume reserves and settles the flat run floor when it completes. A resume that is still paused afterwards is refunded again — you are charged once, for a run that finished, however many times it had to wait.

See the full rate card

Which one

When a different tool is the right call.

The honest answer is often the neighbouring tool. These are the trades.

control_run

If the wall needs a code, this is one call. If it needs a click, control_run is the tool — this one cannot press a button.

control_run
connect_account

When the credential is not yours to hold, do not collect it at all. Send a connect link and let the person complete the whole sign-in themselves.

connect_account
solve_captcha

A CAPTCHA is not a verification code. solve_captcha hands that specific wall to the solver.

solve_captcha

Questions

submit_verification, answered.

Can the platform fetch the code itself?
Often, yes — and then no pause happens at all. Connect an IMAP inbox (POST /api/v1/email-inbox, validated against a real IMAP connection before it is stored) or a phone number, and the engine’s email-first path reads and fills the emailed or texted code itself. submit_verification is the fallback for the codes it cannot reach.
What is the difference between sessionId and token?
They come from different pause mechanics. A synchronous or async run parks a browser session in the engine and returns its sessionId. A streamed run holds open an SSE and emits an await-user event with a one-time token. Pass back whichever you were handed; sending neither is an error.