Skip to main content

Wallet Owner API v3

The Owner API is how software drives a wallet: create it, read balances, build and finalise transfers, verify proofs. For most integrations it is the primary surface.

  • Endpoint: http://127.0.0.1:3420/v3/owner, started with epic-wallet owner_api
  • Protocol: JSON-RPC 2.0 over HTTP POST
  • Credential: the token returned by open_wallet, which takes the wallet password
  • Encryption: an ECDH handshake wraps every call after the first

Send the token inside the envelope on every method that declares one. Keep the port on loopback. See owner access on the wallet.

Methods by what they can do

Can spend funds

Can spend funds These seven build, complete or abandon transfers.

MethodPurpose
init_send_tx()Select inputs and build the first round of a slate
tx_lock_outputs()Reserve the selected inputs. Required in a manual send sequence. Takes token, slate, participant_id and addr_to
finalize_tx()Complete the aggregate signature
post_tx()Broadcast to the network
issue_invoice_tx()Create a payment request
process_invoice_tx()Fund someone else's payment request
cancel_tx()Abandon a transfer and release its reserved outputs

Destructive

Destructive Deletes local wallet data.

MethodEffect
delete_wallet()Deletes the wallet

Exposes a secret

get_mnemonic() returns the recovery phrase.

Changes wallet state

change_password() re-encrypts the seed. scan() rebuilds output state.

Read only

Read only Safe for anything you would allow to read your balance.

accounts(), retrieve_outputs(), retrieve_txs(), retrieve_summary_info(), node_height(), get_stored_tx(), get_public_address(), get_public_proof_address(), get_updater_messages().

Wallet lifecycle

create_config(), create_wallet(), open_wallet(), close_wallet(), get_top_level_directory(), set_top_level_directory(), create_account_path(), set_active_account().

open_wallet returns the token that every other call requires.

Proofs

retrieve_payment_proof(), verify_payment_proof(), proof_address_from_onion_v3(), verify_slate_messages(). See payment proofs.

Configuration and background updates

set_tor_config(), set_epicbox_config(), start_updater(), stop_updater().

Transport

init_secure_api().

The encrypted handshake

Every call after init_secure_api travels inside an encrypted envelope. The parameters are fixed and declared at api/src/owner_rpc_s.rs:1453: AES-256 in GCM mode, a 12-byte nonce, a 16-byte tag appended to the ciphertext, and empty additional authenticated data.

  1. Generate a secp256k1 keypair in your client.
  2. Call init_secure_api with your compressed public key as hex in ecdh_pubkey. The wallet returns its own in the same form.
  3. Multiply the wallet's public point by your private scalar and keep the 32-byte x coordinate. That is the AES-256 key (api/src/owner_rpc_s.rs:2433).
  4. Serialise the call you want as a complete JSON-RPC request object. That inner request is what gets encrypted, and it is where the token and the method params go.
  5. Encrypt it under a fresh 12-byte nonce and base64 the ciphertext with its tag appended.
  6. Post the method encrypted_request_v3 with two params, nonce as hex and body_enc as that base64 string. The envelope has no other fields (api/src/types.rs:59).
  7. The reply is encrypted_response_v3 carrying its own nonce and body_enc. Decrypt with the same key to recover the inner JSON-RPC response, which then has its own Ok or Err envelope.
  8. open_wallet is the first call to send through the envelope. It returns the token every other method takes.
{"jsonrpc": "2.0", "id": 1, "method": "encrypted_request_v3", "params": {"nonce": "ef32...", "body_enc": "e0bcd..."}}

examples/python/epic_wallet.py implements the sequence, including the second unwrap of the decrypted body. The client is listed in full on connect and read.

Reading outputs and transactions

retrieve_outputs and retrieve_txs take limit, offset and sort_order.

InitTxArgs

Controls input selection and transaction shape.

FieldTypeMeaning
src_acct_namestring, optionalSource account. Null uses the active account
amountu64Amount in freemen. 1 EPIC is 100000000
minimum_confirmationsu64Confirmations required before an output is eligible
max_outputsu32Maximum number of inputs to select
num_change_outputsu32How many change outputs to create
selection_strategy_is_use_allboolTrue consolidates every eligible output; false selects the minimum
messagestring, optionalMessage committed into the slate
target_slate_versionu16, optionalSlate version to emit, 2 or 3
ttl_blocksu64, optionalExpiry in blocks. Defaults to none
payment_proof_recipient_addressstring, optionalRequests a payment proof
estimate_onlybool, optionalCompute the fee without reserving anything
send_argsobject, optionalDestination and transport, to run the whole exchange in one call

Additional behaviour:

selection_strategy_is_use_all has privacy consequences. True consolidates your outputs into one transaction, which links them together for anyone analysing the chain. False keeps them separate at the cost of a larger UTXO set later.

A payment proof needs slate V3. payment_proof_recipient_address puts the proof fields in the slate, and only V3 carries them. Delivery over epicbox converts the slate to V2, so a transfer sent that way completes and yields no proof. Pick the transport first: choose the transport accordingly.

ttl_blocks does not release outputs on expiry. See outputs and locking.

src_acct_name names the source account for one call. A label that accounts does not return resolves to the active account (libwallet/src/api_impl/owner.rs:383). See accounts.

send_args runs the exchange inside the call. It delivers the slate, then finalises and posts if you asked it to, so the call blocks for as long as the counterparty takes.

With send_args.method set to epicbox, the call returns the round-one slate as soon as it is posted to the relay and the inputs are locked (api/src/owner.rs:761). finalize and post_tx apply to the http and keybase paths. On the epicbox path the wallet's own subscription finalises and posts when the counterparty's reply arrives, which is also where the mempool wait happens.

Fees

The fee is a function of transaction shape, not of network demand:

fee = max(4 × outputs + kernels − inputs, 1) × 0.001 EPIC

A typical two-input, two-output, one-kernel transfer costs 700,000 freemen, which is 0.007 EPIC. Because no base fee is supplied by the wallet, there is no fee market to bid into.

Version 2

An earlier, unencrypted Owner API with 17 methods is served from the same listener, at /v2/owner. Its methods take no token. New work should target v3, and the listener belongs on loopback.

Full method reference

Source

Next