module Api module V1 class SmsController < ApplicationController include ApiAuthenticatable include RateLimitable include Pagy::Backend # POST /api/v1/sms/send def send_sms return unless rate_limit_by_api_key!(limit: 100, period: 1.minute) phone_number = params.require(:to) message_body = params.require(:message) # Validate phone number phone = Phonelib.parse(phone_number) unless phone.valid? render json: { error: "Invalid phone number format" }, status: :unprocessable_entity return end # Create outbound SMS message sms = SmsMessage.create!( direction: "outbound", phone_number: phone.e164, message_body: message_body, status: "queued" ) render json: { success: true, message_id: sms.message_id, status: sms.status }, status: :accepted rescue ActionController::ParameterMissing => e render json: { error: e.message }, status: :bad_request end # GET /api/v1/sms/status/:message_id def status message_id = params.require(:message_id) sms = SmsMessage.find_by!(message_id: message_id) render json: { message_id: sms.message_id, status: sms.status, sent_at: sms.sent_at, delivered_at: sms.delivered_at, failed_at: sms.failed_at, error_message: sms.error_message } end # GET /api/v1/sms/received def received query = SmsMessage.inbound.recent # Filter by phone number if provided if params[:phone_number].present? query = query.where(phone_number: params[:phone_number]) end # Filter by date if provided if params[:since].present? since_time = Time.parse(params[:since]) query = query.where("created_at >= ?", since_time) end # Paginate results pagy, messages = pagy(query, items: params[:limit] || 50) render json: { messages: messages.map { |sms| { message_id: sms.message_id, from: sms.phone_number, message: sms.message_body, received_at: sms.created_at } }, total: pagy.count, page: pagy.page, pages: pagy.pages } rescue ArgumentError => e render json: { error: "Invalid date format" }, status: :bad_request end end end end