Stage 2 of the two-stage enrollment flow — commits the user’s signed session-key and creates the portfolio.
flowId, accountIndex, and
agentAddress returned by POST /v2/enroll/signature, plus the user’s
signature over the merkle root, and creates the full v2 portfolio state in a
single atomic transaction:
vaults table so the rebalance engine can find session-key bytes for
the freshly enrolled vaults.
x-api-key header (required)enroll:write(tenantId, apiKeyId, "POST /v2/enroll", flowId)
via the v2_idempotency_keys store, with a 24-hour TTL:
flowId with the same body returns the cached response.409 IDEMPOTENCY_KEY_CONFLICT.409 IDEMPOTENCY_IN_PROGRESS.message.raw from the stage-1
response with the user’s wallet, using viem’s signMessage({ message: { raw } })
or the equivalent wallet primitive (the message is a raw 32-byte merkle root;
EIP-191 prefix is applied by the verifier on the server side).
Common error responses:
400 for an invalid request body, expired flow, mismatched signature, or
invalid strategy ownership401 when x-api-key header is missing or the key is invalid403 when the API key lacks the enroll:write scope409 IDEMPOTENCY_IN_PROGRESS when an earlier request with the same flowId
is still running409 IDEMPOTENCY_KEY_CONFLICT when the same flowId is reused with a
different request body409 PORTFOLIO_ALREADY_EXISTS when the user is already enrolled at the
given accountIndex500 on unexpected server errors