Skip to main content
When a transaction requires human approval — because the destination is new and the amount exceeds the micro-threshold — any Nebula payment tool will return a confirmation_required response instead of executing the transaction. await_confirmation lets your agent wait for the human’s decision by polling with the confirmation_id from that response. Because Nebula’s Hub is serverless, each call polls for a bounded amount of time (up to 25 seconds). If the human has not yet responded, the tool returns pending and your agent should immediately call again with the same confirmation_id. Continue polling until the status changes to approved, rejected, or expired.

Parameters

confirmation_id
string
required
The confirmation ID returned in the confirmation_required response from the original tool call. This value is stable — use the same ID across all polling iterations.
timeout_seconds
integer
How long (in seconds) this single call should wait for a response before returning. Defaults to 15. Maximum is 25. If the human has not acted within this window, the tool returns pending — the transaction is not cancelled; call again to continue waiting.

Response states

status
string
The outcome of this polling attempt. One of: approved, rejected, pending, or expired.
StatusMeaning
approvedThe human approved the transaction; it has been executed on-chain.
rejectedThe human explicitly denied the transaction; it has been cancelled.
pendingNo decision yet within the polling window. Re-call with the same confirmation_id.
expiredThe confirmation timed out without a human decision. The transaction has been cancelled.

Where humans approve

The approving human visits the Approvals tab at nebulaonchain.xyz or navigates directly to /approve/:id (substituting the confirmation_id). Approvals can be made on any device.
Each call to await_confirmation waits at most 25 seconds. If the response is pending, you must call again with the same confirmation_id — do not generate a new one or re-submit the original transaction.

Re-polling pattern

# Pseudocode — poll until a final decision is received
confirmation_id = original_tool_response.confirmation_id

loop:
  result = await_confirmation(
    confirmation_id = confirmation_id,
    timeout_seconds = 20
  )

  if result.status == "approved":
    # Transaction has executed — proceed with next step
    break

  elif result.status == "rejected":
    # Human denied the request — handle gracefully
    break

  elif result.status == "expired":
    # No decision in time — transaction was cancelled
    break

  elif result.status == "pending":
    # Still waiting — loop immediately with the same ID
    continue

Examples

Tool call
await_confirmation request
{
  "tool": "await_confirmation",
  "input": {
    "confirmation_id": "conf_01HZ4XM7KPQR2NSTV8WY3ZA6B",
    "timeout_seconds": 20
  }
}
Approved response
await_confirmation — approved
{
  "status": "approved",
  "confirmation_id": "conf_01HZ4XM7KPQR2NSTV8WY3ZA6B",
  "message": "Transfer of 30.00 USDC approved by human operator.",
  "tx_hash": "e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8"
}
Rejected response
await_confirmation — rejected
{
  "status": "rejected",
  "confirmation_id": "conf_01HZ4XM7KPQR2NSTV8WY3ZA6B",
  "message": "Transfer denied by human operator."
}
Pending response
await_confirmation — pending
{
  "status": "pending",
  "confirmation_id": "conf_01HZ4XM7KPQR2NSTV8WY3ZA6B",
  "message": "Awaiting human decision. Call again with the same confirmation_id."
}
Expired response
await_confirmation — expired
{
  "status": "expired",
  "confirmation_id": "conf_01HZ4XM7KPQR2NSTV8WY3ZA6B",
  "message": "Confirmation window elapsed without a decision. Transaction cancelled."
}