0.0
The project is in a healthy, maintained state
A lightweight Ruby wrapper for the NOWPayments API that handles cryptocurrency payments, invoices, and webhooks
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Runtime

~> 2.0
 Project Readme

NOWPayments Ruby SDK

Gem Version License: MIT

Production-ready Ruby wrapper for the NOWPayments API. Accept cryptocurrency payments with minimal code.

Why NOWPayments?

  • 150+ cryptocurrencies - Bitcoin, Ethereum, USDT, and more
  • No KYC required - Accept payments immediately
  • Instant settlement - Real-time payment processing
  • Low fees - Competitive transaction costs
  • Global reach - Accept payments from anywhere

Installation

Add to your Gemfile:

gem 'nowpayments', git: 'https://github.com/Sentia/nowpayments'

Or install directly:

gem install nowpayments

Quick Start

require 'nowpayments'

# Initialize client (sandbox for testing, production when ready)
client = NOWPayments::Client.new(
  api_key: ENV['NOWPAYMENTS_API_KEY'],
  sandbox: true
)

# Create a payment
payment = client.create_payment(
  price_amount: 100.0,
  price_currency: 'usd',
  pay_currency: 'btc',
  order_id: 'order-123',
  ipn_callback_url: 'https://yourdomain.com/webhooks/nowpayments'
)

puts "Payment address: #{payment['pay_address']}"
puts "Amount: #{payment['pay_amount']} BTC"
puts "Status: #{payment['payment_status']}"

Features

🎉 Complete API Coverage - 57 Methods, 100% Coverage!

11 API Modules with Full Implementation:

  1. Authentication (5 methods) - JWT token management for protected endpoints
  2. Status (1 method) - API health checks
  3. Currencies (3 methods) - Available cryptocurrencies and details
  4. Payments (4 methods) - Create and track cryptocurrency payments
  5. Invoices (3 methods) - Hosted payment pages with status tracking
  6. Estimates (2 methods) - Price calculations and minimum amounts
  7. Mass Payouts (8 methods) - Batch withdrawals with 2FA verification
  8. Conversions (3 methods) - Currency conversions at market rates
  9. Subscriptions (9 methods) - Recurring payment plans and billing
  10. Custody/Sub-accounts (11 methods) - User wallet management for marketplaces
  11. Fiat Payouts (8 methods) - Beta: Crypto to fiat withdrawals

Security & Production Ready:

  • JWT Authentication - Bearer token support for sensitive operations
  • Webhook Verification - HMAC-SHA512 signature validation
  • Constant-time comparison - Prevents timing attacks
  • Comprehensive error handling - 8 exception classes with detailed messages
  • 100% tested - 23 passing tests, RuboCop clean

Complete Method List (57 Methods)

Authentication (5 methods) - JWT token management
  • authenticate(email:, password:) - Get JWT token (5-min expiry)
  • jwt_token(email:, password:) - Get token with auto-refresh
  • jwt_expired? - Check if token is expired
  • clear_jwt_token - Clear stored token
  • jwt_time_remaining - Seconds until expiry
Status & Currencies (4 methods) - API health and currency info
  • status - Check API status
  • currencies(fixed_rate: nil) - Get available currencies
  • full_currencies - Detailed currency information
  • merchant_coins - Your enabled currencies
Payments (4 methods) - Standard cryptocurrency payments
  • create_payment(...) - Create new payment
  • payment(payment_id) - Get payment status
  • payments(limit:, page:, ...) - List payments with filters
  • update_payment_estimate(payment_id) - Update exchange rate
Invoices (3 methods) - Hosted payment pages
  • create_invoice(...) - Create invoice with payment page
  • create_invoice_payment(...) - Create payment by invoice ID
  • invoice(invoice_id) - Get invoice status
Estimates (2 methods) - Price calculations
  • estimate(amount:, currency_from:, currency_to:) - Price estimate
  • min_amount(currency_from:, currency_to:) - Minimum payment amount
Mass Payouts (8 methods) - Batch withdrawals (JWT required)
  • balance - Get account balance
  • create_payout(withdrawals:, ...) - Create batch payout (JWT)
  • verify_payout(batch_withdrawal_id:, verification_code:) - 2FA verify (JWT)
  • payout_status(payout_id) - Get payout status
  • list_payouts(limit:, offset:) - List all payouts (JWT)
  • validate_payout_address(address:, currency:, ...) - Validate address
  • min_payout_amount(currency:) - Minimum payout amount
  • payout_fee(currency:, amount:) - Calculate payout fee
Conversions (3 methods) - Currency conversions (JWT required)
  • create_conversion(from_currency:, to_currency:, amount:) - Convert crypto (JWT)
  • conversion_status(conversion_id) - Check conversion status (JWT)
  • list_conversions(limit:, offset:) - List all conversions (JWT)
Subscriptions (9 methods) - Recurring payments
  • subscription_plans - List all subscription plans
  • create_subscription_plan(plan_data) - Create new plan
  • update_subscription_plan(plan_id, plan_data) - Update plan
  • subscription_plan(plan_id) - Get plan details
  • create_subscription(plan_id:, email:) - Create subscription
  • list_recurring_payments(...) - List recurring payments with filters
  • recurring_payment(subscription_id) - Get subscription details
  • delete_recurring_payment(subscription_id) - Cancel subscription (JWT)
  • subscription_payments(subscription_id) - List subscription payments
Custody/Sub-accounts (11 methods) - User wallet management
  • create_sub_account(user_id:) - Create user account
  • sub_account_balance(user_id) - Get user balance
  • sub_account_balances - Get all balances
  • list_sub_accounts(...) - List all sub-accounts
  • transfer_between_sub_accounts(...) - Transfer between users (JWT)
  • create_sub_account_deposit(user_id:, currency:, ...) - Generate deposit address
  • create_sub_account_payment_deposit(...) - Payment to sub-account
  • transfer_to_sub_account(user_id:, currency:, amount:) - Deposit to user
  • withdraw_from_sub_account(user_id:, currency:, amount:) - Withdraw from user (JWT)
  • sub_account_transfer(transfer_id) - Get transfer details
  • sub_account_transfers(...) - List all transfers
Fiat Payouts (8 methods) - Beta: Crypto to fiat (JWT required)
  • fiat_payout_payment_methods(fiat_currency: nil) - Available payment methods (JWT)
  • create_fiat_payout_account(...) - Create payout account (JWT)
  • fiat_payout_accounts(...) - List payout accounts (JWT)
  • update_fiat_payout_account(account_id:, ...) - Update account (JWT)
  • create_fiat_payout(...) - Create fiat payout (JWT)
  • fiat_payout_status(payout_id) - Get payout status (JWT)
  • fiat_payouts(...) - List all fiat payouts with filters (JWT)
  • fiat_payout_rates(...) - Get conversion rates (JWT)

Built for Production

  • Comprehensive error handling - 8 exception classes with detailed messages
  • Faraday middleware - Automatic error mapping and retries
  • Tested - 23 passing tests with VCR cassettes for integration
  • Rails-ready - Drop-in Rack middleware for webhook verification
  • Type-safe - All responses return Ruby Hashes from parsed JSON

Usage Examples

Accept Payment on Your Site

# 1. Create payment
payment = client.create_payment(
  price_amount: 49.99,
  price_currency: 'usd',
  pay_currency: 'btc',
  order_id: "order-#{order.id}",
  order_description: 'Pro Plan - Annual',
  ipn_callback_url: 'https://example.com/webhooks/nowpayments'
)

# 2. Show payment address to customer
@payment_address = payment['pay_address']
@payment_amount = payment['pay_amount']

# 3. Check status
status = client.payment(payment['payment_id'])
# => {"payment_status"=>"finished", ...}

Hosted Invoice Page

# Create invoice with hosted payment page
invoice = client.create_invoice(
  price_amount: 99.0,
  price_currency: 'usd',
  order_id: "inv-#{invoice.id}",
  success_url: 'https://example.com/thank-you',
  cancel_url: 'https://example.com/checkout'
)

# Redirect customer to payment page
redirect_to invoice['invoice_url']
# Customer can choose from 150+ cryptocurrencies

Custody API - Sub-accounts (Marketplaces & Casinos)

# Create sub-account for a user
sub_account = client.create_sub_account(user_id: user.id)
# => {"id"=>123, "user_id"=>456, "created_at"=>"2025-11-01T..."}

# Generate deposit address for user's BTC wallet
deposit = client.create_sub_account_deposit(
  user_id: user.id,
  currency: 'btc'
)
# => {"address"=>"bc1q...", "currency"=>"btc"}

# Check user's balance
balances = client.sub_account_balances(user_id: user.id)
# => {"balances"=>{"btc"=>0.05, "eth"=>1.2}}

# Transfer funds to sub-account
transfer = client.transfer_to_sub_account(
  user_id: user.id,
  currency: 'btc',
  amount: 0.01
)

# Process withdrawal
withdrawal = client.withdraw_from_sub_account(
  user_id: user.id,
  currency: 'btc',
  amount: 0.005
)

JWT Authentication (Required for Advanced Features)

Some endpoints require JWT authentication (expires every 5 minutes):

# Authenticate to get JWT token
client.authenticate(
  email: 'your_email@example.com',
  password: 'your_password'
)
# Token is automatically stored and injected in subsequent requests

# Check token status
client.jwt_expired? # => false
client.jwt_time_remaining # => 287 (seconds)

# JWT is required for these endpoints:
# - Mass Payouts (create_payout, verify_payout, list_payouts)
# - Conversions (create_conversion, conversion_status, list_conversions)
# - Custody Operations (transfer_between_sub_accounts, write_off_sub_account_balance)
# - Recurring Payments (delete_recurring_payment)

# Example: Create payout (requires JWT)
client.authenticate(email: 'your@email.com', password: 'password')
payout = client.create_payout(
  withdrawals: [
    {
      address: 'TEmGwPeRTPiLFLVfBxXkSP91yc5GMNQhfS',
      currency: 'trx',
      amount: 10
    }
  ],
  payout_description: 'Weekly payouts'
)

# Verify payout with 2FA code (from Google Authenticator)
client.verify_payout(
  batch_withdrawal_id: payout['id'],
  verification_code: '123456'
)

# Token auto-refresh pattern
def ensure_authenticated(client, email, password)
  return unless client.jwt_expired?
  client.authenticate(email: email, password: password)
end

# Before JWT-required operations
ensure_authenticated(client, EMAIL, PASSWORD)
payouts = client.list_payouts(limit: 10, offset: 0)

# Clear token when done (optional, for security)
client.clear_jwt_token

See examples/jwt_authentication_example.rb for complete usage patterns.

Currency Conversions (JWT Required)

Convert between cryptocurrencies at market rates:

# Authenticate first
client.authenticate(email: 'your@email.com', password: 'password')

# Create conversion
conversion = client.create_conversion(
  from_currency: 'btc',
  to_currency: 'eth',
  amount: 0.1
)
# => {"conversion_id" => "conv_123", "status" => "processing", ...}

# Check conversion status
status = client.conversion_status(conversion['conversion_id'])
# => {"status" => "completed", "from_amount" => 0.1, "to_amount" => 2.5, ...}

# List all conversions
conversions = client.list_conversions(limit: 10, offset: 0)

Fiat Payouts (Beta - JWT Required)

Withdraw cryptocurrency to fiat bank accounts:

# Authenticate first
client.authenticate(email: 'your@email.com', password: 'password')

# Get available payment methods
methods = client.fiat_payout_payment_methods(fiat_currency: 'EUR')
# => {"result" => [{"provider" => "transfi", "methods" => [...]}]}

# Create payout account
account = client.create_fiat_payout_account(
  provider: 'transfi',
  fiat_currency: 'EUR',
  account_data: {
    accountHolderName: 'John Doe',
    iban: 'DE89370400440532013000'
  }
)
# => {"result" => {"id" => "acc_123", ...}}

# Get conversion rates
rates = client.fiat_payout_rates(
  crypto_currency: 'btc',
  fiat_currency: 'EUR',
  crypto_amount: 0.1
)
# => {"result" => {"fiatAmount" => "2500.00", "rate" => "25000.00", ...}}

# Create fiat payout
payout = client.create_fiat_payout(
  account_id: account['result']['id'],
  crypto_currency: 'btc',
  crypto_amount: 0.1
)
# => {"result" => {"id" => "payout_123", "status" => "PENDING", ...}}

# Check payout status
status = client.fiat_payout_status(payout['result']['id'])
# => {"result" => {"status" => "FINISHED", ...}}

# List all fiat payouts with filters
payouts = client.fiat_payouts(
  status: 'FINISHED',
  fiat_currency: 'EUR',
  limit: 10,
  page: 0
)

Webhook Verification (Critical!)

Always verify webhook signatures to prevent fraud:

# app/controllers/webhooks_controller.rb
class WebhooksController < ApplicationController
  skip_before_action :verify_authenticity_token
  
  def nowpayments
    # Verify signature - raises SecurityError if invalid
    payload = NOWPayments::Rack.verify_webhook(
      request,
      ENV['NOWPAYMENTS_IPN_SECRET']
    )
    
    # Process payment status
    order = Order.find_by(id: payload['order_id'])
    
    case payload['payment_status']
    when 'finished'
      order.mark_paid!
      OrderMailer.payment_received(order).deliver_later
    when 'failed', 'expired'
      order.cancel!
    when 'partially_paid'
      # Customer sent wrong amount
      logger.warn "Underpaid: #{payload['actually_paid']} vs #{payload['pay_amount']}"
    end
    
    head :ok
    
  rescue NOWPayments::SecurityError => e
    logger.error "Invalid webhook signature: #{e.message}"
    head :forbidden
  end
end

# config/routes.rb
post '/webhooks/nowpayments', to: 'webhooks#nowpayments'

Error Handling

begin
  payment = client.create_payment(...)
  
rescue NOWPayments::AuthenticationError
  # Invalid API key
  
rescue NOWPayments::BadRequestError => e
  # Invalid parameters
  puts "Error: #{e.message}"
  puts "Details: #{e.body}"
  
rescue NOWPayments::RateLimitError => e
  # Too many requests
  retry_after = e.headers['Retry-After']
  
rescue NOWPayments::ServerError
  # NOWPayments server error
  
rescue NOWPayments::ConnectionError
  # Network error
end

Documentation

Testing with Sandbox

# Use sandbox for development
client = NOWPayments::Client.new(
  api_key: ENV['NOWPAYMENTS_SANDBOX_API_KEY'],
  ipn_secret: ENV['NOWPAYMENTS_SANDBOX_IPN_SECRET'],
  sandbox: true
)

# All API calls go to sandbox environment
payment = client.create_payment(...)

Get sandbox credentials:

  1. Create account at https://account-sandbox.nowpayments.io/
  2. Generate API key from dashboard
  3. Generate IPN secret for webhooks
  4. Add to .env file

Configuration

# .env
NOWPAYMENTS_API_KEY=your_production_api_key
NOWPAYMENTS_IPN_SECRET=your_ipn_secret

# Testing
NOWPAYMENTS_SANDBOX_API_KEY=your_sandbox_api_key
NOWPAYMENTS_SANDBOX_IPN_SECRET=your_sandbox_ipn_secret

Examples

See the examples/ directory:

# API usage demo
cp .env.example .env
# Add your sandbox credentials to .env
ruby examples/simple_demo.rb

# Webhook receiver (Sinatra)
ruby examples/webhook_server.rb
# Use ngrok to expose: ngrok http 4567

Development

# Install dependencies
bundle install

# Run tests
bundle exec rspec

# Run tests with coverage
COVERAGE=true bundle exec rspec

# Lint code
bundle exec rubocop

# Interactive console
bundle exec rake console

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b feature/my-feature)
  3. Run tests (bundle exec rspec)
  4. Commit your changes (git commit -am 'Add feature')
  5. Push to the branch (git push origin feature/my-feature)
  6. Create a Pull Request

Security

Report security vulnerabilities to: security@yourdomain.com

Never commit API keys or secrets. Always use environment variables.

License

MIT License - see LICENSE.txt

Support