melaya

Current production scope: Agent Builder and Mobile Device Control are available now. Melaya Trading namespaces are preview-only and not generally available; do not use them with real funds.

Official SDK for the Melaya Agent Builder and flagship Mobile Device Control APIs. Trading namespaces are included only as a preview of a later product.

  • Zero runtime gem dependencies (stdlib net/http, openssl, json only).
  • Full Agent Builder lifecycle: projects, pipelines, templates, Connectors, HITL, evals, events, billing, team, and runner management.
  • Catalogs of 1,500+ scoped tools, 100+ specialized subagents, and 20+ model providers (runtime catalog endpoints are the source of truth).
  • Pure Ruby WebSocket client (RFC 6455) — no external gem required for streaming.

Install

Add to your Gemfile:

gem "melaya", path: "path/to/sdk-ruby"   # local checkout

Or once published to RubyGems:

gem install melaya

Agent Builder & Device Control

Quick start: pair a phone

require "melaya"

melaya = Melaya::Client.new(api_key: ENV["MELAYA_API_KEY"])  # keys are prefixed mk_

pairing = melaya.agents.phone.pair
puts "Pairing code: #{pairing["code"]} (expires in #{pairing["expiresInSeconds"]}s)"
# Enter the code in the Melaya APK on the phone

devices = melaya.agents.phone.list_devices
apps    = melaya.agents.phone.list_apps

melaya.agents.phone.set_allowed_apps(["com.android.chrome"])

A Melaya platform key is required. "No app API required" means Device Control operates the target app through its user interface; it does not mean the Melaya SDK is unauthenticated.

Quick start: run an agent pipeline

Configure provider credentials through Melaya Connectors first. Never include a provider key in pipeline configuration or per-run overrides.

melaya.agents.pipelines.create(
  name:    "mobile-review",
  project: "Operations",
  model_provider: "anthropic",
  model_name:     "claude-sonnet-4-6",
  agents: [{
    "name"        => "mobile-operator",
    "role"        => "Careful mobile operator",
    "instruction" => "Read before acting. Never send, publish, or delete.",
    "agent_tools" => [
      "phone_get_screen_tree",
      "phone_current_app",
      "phone_open_app",
      "phone_click_text",
      "phone_back",
      "phone_wait"
    ]
  }],
  steps: [{ "kind" => "agent", "agent" => { "name" => "mobile-operator" } }],
  maxCostUsd: 1.00
)

run    = melaya.agents.pipelines.run("mobile-review", project: "Operations")
run_id = run["run_id"]

melaya.agents.phone.register_active_run(run_id)

status = melaya.agents.pipelines.run_status("mobile-review", run_id)

# Real-time run events over Socket.IO (connects lazily on first use)
melaya.events.on_run_update(run_id) { |e| puts e["event_type"] }

Trading quick start (preview)

require "melaya"

melaya = Melaya::Client.new(api_key: ENV["MELAYA_API_KEY"])  # keys are prefixed mk_

# REST — normalized ticker from any of 70+ venues
t = melaya.market.ticker(exchange: "binance", symbol: "BTC/USDT", market: "spot")
puts t["last"], t["bid"], t["ask"]

# Order book
ob = melaya.market.orderbook(exchange: "bybit", symbol: "BTC/USDT", market: "spot", limit: 20)

# Candles
candles = melaya.market.ohlcv(exchange: "okx", symbol: "ETH/USDT", timeframe: "1h", limit: 200)

Streaming (preview)

# Live ticker (block form — closes when block returns)
melaya.stream.ticker(exchange: "binance", symbol: "BTC/USDT", market: "spot") do |frame|
  puts frame["last"]
  break  # close after first frame
end

# Liquidation firehose
melaya.stream.liquidations(exchange: "binance") do |ev|
  puts ev["side"], ev["notional"]
  break
end

Trading (preview)

# Account: connected exchange keys and usage
keys  = melaya..keys    # [{ "apiKeyId" => "BINANCEUSDM_0", "exchange" => "binanceusdm", ... }]
usage = melaya..usage

# Strategies — launch immediately. Paper (dry_run: true) needs no exchange key.
# SDK-launchable strategies are `custom` Rhai definitions.
result = melaya.strategies.create(
  name:          "my-bot",
  strategy_type: "custom",
  exchange:      "binanceusdm",
  symbol:        "BTC/USDT:USDT",
  market:        "FUTURES",
  dry_run:       true,
  params: {
    "language"   => "rhai",
    "definition" => 'fn evaluate() { emit_long(param("qty")); }',
    "qty"        => 0.001,
  }
)
sid = result["strategyId"]
melaya.strategies.pause(sid)
melaya.strategies.resume(sid)
trades = melaya.strategies.trades(sid)

# Paper trading (sim broker) — synthetic fills, no venue state
bal  = melaya.sim.balance(strategy_id: sid)
fill = melaya.sim.create_order(
  strategy_id: sid,
  exchange: "binanceusdm",
  symbol: "BTC/USDT:USDT",
  side: "buy",
  type: "market",
  amount: 0.001,
  market: "FUTURES"
)

# Backtest on the Rust engine
r = melaya.backtest.start(
  "strategyType" => "custom",
  "exchange"     => "binance",
  "symbol"       => "BTC/USDT",
  "timeframe"    => "1h",
  "since_ms"     => (Time.now.to_i - 90 * 86400) * 1000,
  "until_ms"     => Time.now.to_i * 1000,
  "language"     => "rhai",
  "definition"   => 'fn evaluate() { emit_long(param("qty")); }',
  "params"       => { "qty" => 0.001 }
)
job_id = r["job_id"]
loop do
  j = melaya.backtest.job(job_id)
  break if %w[done error].include?(j["status"])
  sleep 2
end
result = melaya.backtest.results(job_id)

# Private streaming (ticket minted automatically)
melaya.stream.strategies do |ev|
  puts ev["type"], ev["strategyId"]
  break
end

# Always clean up
melaya.strategies.stop(sid)
melaya.strategies.delete(sid)

Authentication

Create an API key in the dashboard (melaya.org → Settings → API Keys). Keys are prefixed mk_. Every REST call sends the key only as an Authorization: Bearer mk_... header — never in the URL query string. Public WebSocket market-data streams authenticate with ?apiKey= in the wss:// URL (server protocol); private WebSocket streams instead use a short-lived ?wsTicket= that the SDK mints automatically.

Public market-data and account/strategy reads work with the mk_ key alone. Live order placement and live strategy launches additionally require a connected exchange key — connect one in Settings → Connectors, then reference it by apiKeyId. Paper trading and backtesting never touch a venue and need no exchange credentials.

API surface

Agent Builder & platform (GA)

Area Methods
Auth auth.login, verify_mfa, register, verify_signup, resend_verification, me, check, change_password, forgot_password, reset_password, mobile_handoff, permissions, refresh
MFA auth.mfa_status, mfa_setup, mfa_confirm (also via melaya.platform.mfa)
Projects projects.list, create, rename, runner_projects
Connectors connectors.connected_services, set, delete, env_handle, google_oauth_start
Credentials credentials.list, connected_services, get, set, delete, test, list_models, plus operator-profile, OAuth, and RAG helpers
Pipelines pipelines.create, get, update, delete_pipeline, list_pipelines, run, run_ids, run_status, cancel_run, outputs, output, preview_code, tools, subagents, instantiate_template, build_with_ai
Runs & traces pipelines.list, recent, count, traces, trace, trace_stats, delete_traces
Schedules pipelines.list_schedules, get_schedule, upsert_schedule, pause_schedule, resume_schedule
Overview pipelines.overview, model_prices, chart_data, cost_breakdown, server_version
Templates templates.list, list_global, list_validated, save, update, duplicate, delete, share, share_targets, list_assignments, assign(id, user_id: \ project_id:), unassign(id, user_id: \ project_id:)
Phone phone.pair, list_devices, revoke_device, screen_tree, list_apps, set_allowed_apps, register_active_run
HITL hitl.pending, history, approve, reject, bulk_decide, run_tool_stats, run_tool_stats_by_agent, run_messages, run_tool_calls
Evals evals.list_runs, summary, run_detail, compare, memory_graph, run_memory, crew_memory, benchmarks
Events events.on_run_update, on_init_phase, on_project_event, on_hitl_approval, on_pipeline_created, on_pipeline_updated, on_pipeline_deleted, leave_run, leave_project, close
Billing billing.subscription, create_checkout, create_portal, plans, credits, ai_credits, portfolio_ideas_credits, risk_monitoring_credits
Accounts accounts.export_data, remove_key, update_profile
Runner runner.create_token, list_tokens, revoke_token
Team team.list_members, invite, create_invite_link, accept_invite, update_member_role, remove_member, get_pipeline_visibility, set_pipeline_visibility
Assistant assistant.get_profile, set_profile
Bugs bugs.create, list_mine, get, add_comment, list_notifications, mark_notifications_read

Every area is also reachable through the domain namespaces: melaya.agents.* (pipelines/runs, hitl, assistant, phone, evals, models) and melaya.platform.* (projects, credentials, connectors, billing, team, templates, overview, runner, auth, mfa, accounts, bugs, events).

Trading (preview — not generally available)

Area Methods
Reference market.list_exchanges, catalog_counts
Market data market.ticker, orderbook, ohlcv, ohlcv_multi, trades, markets, currencies, market_constraints, status, time
Batch / derivatives market.tickers, funding_rates, funding_rate_history, funding_rate_history_multi, open_interest, open_interest_history, open_interest_history_multi, instruments, liquidation_events
Prediction markets market.prediction_markets (polymarket, kalshi, drift_pm, sxbet, azuro, overtime)
Account account.keys, usage, api_key_status
Strategies strategies.create, list, get, pause, resume, stop, delete, update_params, status, performance, executions, trades, logs
AI optimizer strategies.ai_opt_start, ai_opt_status, ai_opt_approve, ai_opt_stop, ai_opt_runs
Paper trading sim.balance, positions, open_orders, my_trades, create_order, cancel_order, list_accounts
Backtesting backtest.start, job, results, trades, sweep, list, favorites, funding_range, cancel, delete, delete_all
Public streaming stream.ticker, orderbook, ohlcv, trades, liquidations
Private streaming stream.strategies, stream.private

Full docs: melaya.org/docs.

License

Apache-2.0