Ruby SDK and CLI for Mixin Network: authenticated REST calls, Safe UTXO transfers, Blaze messaging, network asset catalog, inscriptions, invoices and mix addresses, transaction encoding, and optional MVM (Mixin Virtual Machine) helpers.
The gem aims for parity with the official bot-api-go-client Go SDK and bot-api-nodejs-client Node SDK. See API_COVERAGE.md for the full mapping; run rake mixin_bot:api_coverage to confirm no gaps are marked missing.
Current gem version: 2.2.1 (see CHANGELOG.md for breaking changes and deprecations).
- Ruby ≥ 3.2 (CI runs 3.2, 3.3, and 4.0).
- Bundler 2.5+ recommended, especially on Ruby 4.
- Optional: the
mixinCLI inPATHif you useMixinBot::API#encode_raw_transaction_native/#decode_raw_transaction_nativeor the experimentalMixinBot::NodeCLIhelpers.
Add to your Gemfile:
gem 'mixin_bot'Then:
bundle installOr install the gem directly:
gem install mixin_botThe gem ships the mixinbot executable (see CLI).
Set the fields your flows need. Safe transfers and signing require a spend key (spend_key) in addition to session material.
require 'mixin_bot'
MixinBot.configure do
self.app_id = 'your-app-uuid'
self.client_secret = 'your-client-secret' # OAuth flows
self.session_id = 'your-session-uuid'
self.session_private_key = '...' # seed or full Ed25519 private key; Base64 or hex
self.server_public_key = '...' # pin token / server public key
self.spend_key = '...' # Ed25519 spend private key for Safe UTXO signing
# self.pin = self.spend_key # optional; used where PIN material is required
# self.api_host = 'api.mixin.one'
# self.blaze_host = 'blaze.mixin.one'
# self.debug = true # Faraday response logging
endMixinBot::Configuration accepts common aliases: client_id → app_id, private_key → session_private_key, pin_token → server_public_key. Keys are normalized (e.g. 32-byte Ed25519 seeds expanded to 64-byte signing keys) where appropriate.
api = MixinBot.api # singleton using global config, or MixinBot::API.new(...)
api.me['full_name']
api.assets
api.network_asset('c6d0c728-2624-429b-8e0d-d9d19b6592fa') # public network catalog
api.fetch_user_sessions(['user-uuid'])create_transfer with keyword arguments runs the Safe pipeline (UTXO select → build → verify → sign → submit). You can also call create_safe_transfer explicitly. Configure spend_key first.
result = MixinBot.api.create_transfer(
members: '6ae1c7ae-1df1-498e-8f21-d48cb6d129b5',
asset_id: '965e5c6e-434c-3fa9-b780-c50f43cd955c',
amount: '0.01',
memo: 'payment',
trace_id: SecureRandom.uuid
)
# Multisig: 2-of-3
MixinBot.api.create_safe_transfer(
members: %w[uuid-1 uuid-2 uuid-3],
threshold: 2,
asset_id: '965e5c6e-434c-3fa9-b780-c50f43cd955c',
amount: '0.01'
)Lower-level steps: build_utxos, build_safe_transaction, verify_raw_transaction / create_safe_transaction_request, sign_safe_transaction, send_safe_transaction (batch via requests:).
Aliases aligned with the Go SDK include send_transaction, send_transfer_transaction, and get_transaction_by_id (→ safe_transaction).
If the first argument is a PIN string and you pass opponent_id: (old Messenger transfer shape), create_transfer delegates to create_legacy_transfer (deprecated, warns once). Prefer Safe transfers for new code.
# Legacy only — deprecated
MixinBot.api.create_legacy_transfer(
pin,
asset_id: '...',
opponent_id: '...',
amount: 0.00000001,
trace_id: SecureRandom.uuid
)MixinBot::Client returns MixinBot::Models::ApiEnvelope for REST calls. It wraps the raw JSON so you can use either envelope or flattened shapes:
res = MixinBot.api.client.get('/me')
res['data']['user_id'] # envelope
res['user_id'] # delegated lookup into `data` when present
res.to_h # raw HashMany convenience methods on MixinBot::API still return the inner data hash where that was the historical contract (e.g. #me).
MixinBot::API composes one module per API area (all methods are available on MixinBot.api):
| Module | Examples |
|---|---|
| Me | me, safe_me, update_me, friends, update_preferences, relationship |
| User | user, fetch_users, search_user, create_user, safe_register, migrate_to_safe |
| Session | fetch_user_sessions |
| LegacyUser | upgrade_legacy_user |
| Asset | assets, asset, ticker, fetch_assets, asset_fee, asset_balance |
| NetworkAsset | network_asset, network_ticker, network_asset_search |
| Network | network_assets, network_assets_top |
| Fiat | fiats |
| Chain | network_chain, network_chains, chain_name, chain_id? |
| Transfer | create_transfer, create_safe_transfer, build_utxos, send_transaction, … |
| Transaction | create_safe_keys, build_safe_transaction, verify_raw_transaction, sign_safe_transaction, build_object_transaction, create_object_storage_transaction, … |
| Output | safe_outputs, safe_output, build_threshold_script |
| Deposit | pending_safe_deposits |
| Address (deposit entries) | safe_deposit_entries |
| Snapshot | safe_snapshots, safe_snapshot, create_safe_snapshot_notification |
| LegacySnapshot | snapshots, snapshot, snapshot_by_trace_id, network_snapshots, … |
| Payment | safe_pay_url |
| LegacyPayment | pay_url, verify_payment (deprecated) |
| Multisig | create_safe_multisig_request, safe_multisig_request, create_multisig_raw_tx |
| LegacyMultisig | create_multisig_request, cancel_multisig_request, … |
| LegacyOutput | legacy_outputs, read_multisigs, create_output, … |
| LegacyTransfer | create_legacy_transfer, legacy_transfer |
| LegacyTransaction | build_raw_transaction, create_multisig_transaction, … |
| Inscription | collection, collectible, build_inscribe_transaction, … |
| LegacyCollectible | legacy collectible requests (deprecated) |
| Withdraw | withdrawals, create_withdraw_address, check_address, withdraw_addresses |
| Conversation | conversation, create_group_conversation, join_conversation, … |
| Message | send_message, send_plain_messages, Blaze helpers |
| EncryptedMessage | send_encrypted_*, encrypt_message, decrypt_message |
| Blaze | blaze, start_blaze_connect, blaze_send_plain_text, … |
| Attachment | create_attachment, upload_attachment |
| Auth | oauth_token, authorize_code, access_token, sign_oauth_access_token |
| Pin / Tip | verify_pin, update_pin, update_tip_pin, encrypt_tip_pin, get_tip_node, tip_body_for_* |
| App | favorite_apps, transfer_app_ownership (migrate) |
| Code | read_code, read_multisig_by_code |
| Turn | turn_servers |
| Rpc | rpc_proxy, send_raw_transaction, get_transaction, … |
| ComputerApi | delegates to MixinBot::Computer (get_computer_info, register_computer, …) |
Top-level helpers on MixinBot::API: access_token, encode_raw_transaction, decode_raw_transaction, native variants via mixin CLI.
| Area | Description |
|---|---|
MixinBot::Client |
Faraday HTTP client (JSON, retries, optional debug). |
MixinBot::Configuration |
Credentials and hosts. |
MixinBot::Utils |
Crypto, JWT, encoding, unique_object_id, generate_user_checksum, … |
MixinBot::Transaction |
Encode/decode raw Safe transactions. |
MixinBot::MixAddress |
Parse/build MIX… addresses; request_or_generate_ghost_keys. |
MixinBot::Invoice |
MIN… payment invoices. |
MixinBot::UrlScheme |
mixin:// deep links (scheme_users, scheme_pay, …). |
MixinBot::Computer |
Mixin Computer HTTP API (separate host). |
MixinBot::BotAuth |
Sign bot-platform requests (BotAuth::Client#sign_request). |
MixinBot::Monitor |
YAML monitor messages, report_to_monitor, check_retryable_error. |
MixinBot::UUID, MixinBot::Nfo |
UUID and NFT memo helpers. |
MVM |
Optional MVM namespace: MVM::Bridge, MVM::Nft, MVM::Scan, MVM::Registry. |
API failures raise structured MixinBot::APIError subclasses with code, description, request_id, and behavior helpers (retryable?, throttle?). The full mapping follows the Mixin error codes table — notably 429 → RateLimitError, not ForbiddenError.
Use MixinBot.retryable?(error) for job retry decisions; use error.throttle? on RateLimitError for global backoff. Monitor.check_retryable_error delegates to the same policy.
Local validation errors (ArgumentError, InvalidInvoiceFormatError, …) and InsufficientAppBillingError (billing preflight) are separate from API envelope errors. See lib/mixin_bot/errors.rb.
bot_a = MixinBot::API.new(
app_id: '...',
session_id: '...',
session_private_key: '...',
server_public_key: '...',
spend_key: '...'
)
bot_b = MixinBot::API.new(...) # separate configuration
bot_a.me
bot_b.meBlaze uses a WebSocket after JWT auth. start_blaze_connect yields a Faye::WebSocket::Client; define on_open / on_message / on_error / on_close on the receiver (see examples/blaze.rb). Run an event loop (e.g. EventMachine) in your app.
require 'eventmachine'
require 'mixin_bot'
EM.run do
MixinBot.api.start_blaze_connect do
def on_open(blaze, _event)
blaze.send list_pending_message
end
def on_message(blaze, event)
raw = JSON.parse ws_message(event.data)
blaze.send acknowledge_message_receipt(raw['data']['message_id']) if raw.dig('data', 'message_id')
end
end
endFor outbound messages over an open socket, use blaze_send_plain_text, blaze_send_contact, blaze_send_app_card, and related helpers (parity with Go BlazeClient).
MixinBot::UrlScheme.scheme_pay(
asset_id: '...',
trace_id: SecureRandom.uuid,
recipient_id: '...',
memo: 'hello',
amount: '0.01'
)
client = MixinBot::BotAuth.new_client(MixinBot.api)
token = client.sign_request(Time.now.to_i, bot_user_id, 'GET', '/some/path')Invoke mixinbot (global options: -a / --apihost, -o / --output pretty|json|yaml, -r / --pretty).
When stdout is piped, output defaults to JSON. Use mixinbot schema -o json for machine-readable command discovery. See docs/agent/cli.md.
Subcommands that talk to the API accept -k / --keystore: path to a JSON file or inline JSON (app_id, session_id, session_private_key, server_public_key, spend_key, client_secret, pin, etc.). Without -k, the CLI uses global MixinBot.configure credentials.
| Command | Purpose |
|---|---|
mixinbot call METHOD |
Invoke any MixinBot::API method (-d JSON kwargs, optional positional args). |
mixinbot list [FILTER] |
List callable API methods (grouped by module). |
mixinbot api PATH |
Signed GET/POST via MixinBot::Client (-m, -d, -p, -t). |
mixinbot transfer USER_ID |
Safe transfer (create_safe_transfer; --asset, --amount, …). |
mixinbot legacy-transfer USER_ID |
Deprecated POST /transfers. |
mixinbot safetransfer USER_ID |
Alias for transfer (deprecated name). |
mixinbot authcode |
OAuth authorize code (-c, -s). |
mixinbot encrypt PIN / verifypin / updatetip |
PIN/TIP helpers. |
mixinbot saferegister |
Safe registration (--spend_key). |
mixinbot pay |
Safe payment URL. |
mixinbot utils call METHOD |
Invoke any MixinBot.utils method (-d JSON kwargs). |
mixinbot utils list [FILTER] |
List utils methods. |
mixinbot unique UUID … |
Deterministic UUID. |
mixinbot generatetrace HASH |
Trace UUID from tx hash. |
mixinbot decodetx HEX |
Decode raw transaction. |
mixinbot nftmemo |
NFT mint memo. |
mixinbot rsa / ed25519 |
Key generation. |
mixinbot version |
Gem version. |
Examples:
mixinbot call me -k ~/.mixinbot/keystore.json
mixinbot call safe_outputs -k keystore.json -d '{"asset":"965e5c6e-434c-3fa9-b780-c50f43cd955c","state":"unspent"}'
mixinbot transfer USER_ID -k keystore.json --asset ASSET_ID --amount 0.01Run mixinbot help and mixinbot help COMMAND for details.
- llms.txt — curated documentation index (llmstxt.org format)
- AGENTS.md — repository layout, conventions, and workflows for coding agents
- docs/agent/cli.md — structured
mixinbotoutput, schema introspection, JSON examples - docs/agent/cookbook.md — task recipes (transfers, auth, messaging)
Run mixinbot schema -o json to discover CLI commands programmatically.
- API coverage — API_COVERAGE.md vs bot-api-go-client.
- RDoc —
rake rdoc→doc/index.html. - Online — RubyDoc.info.
- Changelog — CHANGELOG.md.
git clone https://github.com/an-lee/mixin_bot.git
cd mixin_bot
bundle install-
Default suite (offline WebMock stubs):
rake test -
API coverage check:
rake mixin_bot:api_coverage
-
RuboCop —
rakeruns tests + RuboCop. -
Live API (optional):
cp test/config.yml.example test/config.yml LIVE=1 rake test # or: rake test_live
Examples under examples/ expect examples/config.yml (copy from examples/config.yml.example).
GitHub Actions runs on every pull request and on pushes to main:
- Test — Ruby 3.2, 3.3, and 4.0:
bundle exec rake test - RuboCop — Ruby 3.3:
bundle exec rake rubocop - API coverage —
bundle exec rake mixin_bot:api_coverage
Publishing to RubyGems.org is automated when a version tag is pushed:
-
Bump
MixinBot::VERSIONinlib/mixin_bot/version.rband updateCHANGELOG.md. -
Commit and push to
main. -
Create and push a tag matching the gem version (e.g.
v2.1.0for version2.1.0):git tag v2.1.0 git push origin v2.1.0
The Release workflow builds the gem, publishes to RubyGems.org via trusted publishing (GitHub OIDC; trusted publisher for workflow release.yml on an-lee/mixin_bot), and creates a GitHub Release with notes from CHANGELOG.md and the .gem attached. To build without publishing, run the Release workflow manually with dry run enabled.
- Mixin developers documentation
- Mixin API overview
- bot-api-go-client (official Go SDK; parity reference)
- mixin_client_demo (Python)
- mixin-node (Node.js)
MIT — see MIT-LICENSE.