v1

API Reference

Rent disposable phone numbers and receive SMS codes programmatically. Rentals you create through the API show up in the website dashboard as well — it's the same account either way.

Authentication

All endpoints require an API key passed via the Authorization header. Get your key from Settings.

Authorization: Bearer omo_live_...

Example request:

curl https://ohmyotp.com/api/v1/user/me \
  -H "Authorization: Bearer $API_KEY"

Base URL

https://ohmyotp.com/api/v1

Endpoints

GET/api/v1/services

List available services

Returns all services you can rent a number for.

Request

curl https://ohmyotp.com/api/v1/services \
  -H "Authorization: Bearer $API_KEY"

Response

{
  "services": [
    { "id": "AppID-3", "name": "Uber", "price": 0.4, "available": 20, "category": "Food" },
    { "id": "AppID-1", "name": "Walmart", "price": 0.4, "available": 10, "category": "retail" }
  ],
  "total": 2
}
GET/api/v1/services/:id

Service detail

Full metadata for a single service.

Request

curl https://ohmyotp.com/api/v1/services/Uber \
  -H "Authorization: Bearer $API_KEY"
GET/api/v1/balance

Balance + transactions

Your current balance and recent transactions (rental charges, refunds, deposits).

Request

curl https://ohmyotp.com/api/v1/balance \
  -H "Authorization: Bearer $API_KEY"

Response

{
  "balance": 9997.60,
  "transactions": [
    { "type": "rental_charge", "amount": -0.4, "service_id": "Uber", "created_at_unix": 1776276700 }
  ]
}
POST/api/v1/rentals

Rent a number

Creates a new rental. Use the service name (not id) as service_id. Returns the phone number to use.

Request

curl -X POST https://ohmyotp.com/api/v1/rentals \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"service_id":"Uber"}'

Response

{
  "id": "fd7b389f-e678-4676-b937-4fef295a34a4",
  "service_id": "Uber",
  "phone_number": "3026873874",
  "status": "active",
  "cost": 0.4,
  "rented_at": 1776619687,
  "expires_at": 1776620287,
  "sms_messages": []
}
GET/api/v1/rentals/active

Active rentals

Request

curl https://ohmyotp.com/api/v1/rentals/active \
  -H "Authorization: Bearer $API_KEY"
GET/api/v1/rentals/history

Rental history

Query params: status (all | active | completed | expired | cancelled), page, limit (max 200), used (true → only rentals that received an SMS). Each entry includes last_code, last_sms_full_text, last_sms_received_at for the most recent received SMS, plus rentable + rentable_reason indicating whether the phone is eligible for re-rent right now.

Request

curl "https://ohmyotp.com/api/v1/rentals/history?status=all&used=true&limit=20" \
  -H "Authorization: Bearer $API_KEY"
GET/api/v1/rentals/:id

Rental detail (with SMS history)

Returns the full rental including all SMS messages received so far. Poll this to get new codes.

Request

curl https://ohmyotp.com/api/v1/rentals/RENTAL_ID \
  -H "Authorization: Bearer $API_KEY"
GET/api/v1/rentals/:id/code

Latest code (lightweight poll)

Returns just the most recent SMS code — cheaper than the full rental endpoint.

Request

curl https://ohmyotp.com/api/v1/rentals/RENTAL_ID/code \
  -H "Authorization: Bearer $API_KEY"

Response

{
  "rental_id": "fd7b389f...",
  "status": "completed",
  "code": "5384",
  "message": "<Uber> Your code: 5384...",
  "received_at": 1776619718,
  "expires_at": 1776620287
}
POST/api/v1/rentals/:id/cancel

Cancel a rental (release the number)

Releases the rented phone number before it expires. A full refund is issued if no SMS has been received yet; if a code has already arrived, the rental is just marked cancelled without a refund. You can only cancel rentals you own.

Request

curl -X POST https://ohmyotp.com/api/v1/rentals/RENTAL_ID/cancel \
  -H "Authorization: Bearer $API_KEY"

Response

{
  "id": "fd7b389f-e678-4676-b937-4fef295a34a4",
  "status": "cancelled",
  "refund_amount": 0.4,
  "cancelled_at": 1776276800
}
POST/api/v1/rentals/rerent

Re-rent a phone number you used before

Rents a specific phone number you've previously used for the same service. The number must still be in inventory, not expired, and not currently active in another rental. Pass an idempotency_key (≥8 chars) as a query param — replays within ~24h return the same rental instead of double-charging. Use /rentals/history to find phones you've used and check rentable=true on each entry.

Request

curl -X POST "https://ohmyotp.com/api/v1/rentals/rerent?idempotency_key=rerent-20260515-0001" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"service_id":"Uber","phone_number":"3026873874"}'

Response

{
  "id": "9c1cba34-7c9d-4e8e-9f4f-9b9b1c8a4a23",
  "service_id": "Uber",
  "phone_number": "3026873874",
  "status": "active",
  "cost": 0.4,
  "rented_at": 1779000000,
  "expires_at": 1779000600,
  "rerent": true,
  "sms_messages": []
}
POST/api/v1/rentals/rerent/check

Batch-check re-rent eligibility

Check up to 100 phone numbers at once to see which are eligible for re-rent (without actually renting). Useful for rendering a UI list. Each row returns eligible=true/false plus a machine-readable reason (ok, phone_currently_active, phone_expired, phone_not_in_inventory, insufficient_balance, etc.).

Request

curl -X POST https://ohmyotp.com/api/v1/rentals/rerent/check \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "service_id":"Uber",
    "phone_numbers":["3026873874","3125550001"]
  }'

Response

{
  "service_id": "Uber",
  "cost": 0.4,
  "balance": 9999.6,
  "eligible_count": 1,
  "results": [
    { "phone_number": "3026873874", "eligible": true,  "reason": "ok",                     "cost": 0.4 },
    { "phone_number": "3125550001", "eligible": false, "reason": "phone_currently_active", "cost": 0.4 }
  ]
}

Common patterns

Rent a number and wait for SMS

# 1. Create rental
RENTAL=$(curl -s -X POST https://ohmyotp.com/api/v1/rentals \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"service_id":"Uber"}')

RENTAL_ID=$(echo "$RENTAL" | jq -r .id)
PHONE=$(echo "$RENTAL" | jq -r .phone_number)
echo "Phone: $PHONE"

# 2. Poll for code (every 5s, up to 10 min)
for i in $(seq 1 120); do
  CODE=$(curl -s https://ohmyotp.com/api/v1/rentals/$RENTAL_ID/code \
    -H "Authorization: Bearer $API_KEY" | jq -r .code)
  if [ "$CODE" != "null" ]; then
    echo "Got code: $CODE"
    break
  fi
  sleep 5
done

Cancel a rental and get a refund

Full refund if no SMS has been received. If a code already arrived, the rental is just released without a refund.

curl -X POST https://ohmyotp.com/api/v1/rentals/$RENTAL_ID/cancel \
  -H "Authorization: Bearer $API_KEY"

# → { "id": "...", "status": "cancelled", "refund_amount": 0.4 }

Full flow: rent → wait → use → cancel on timeout

#!/bin/bash
# Rent a number, wait up to 2 min for a code, cancel if nothing arrives.

RENTAL=$(curl -s -X POST https://ohmyotp.com/api/v1/rentals \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"service_id":"Uber"}')

RENTAL_ID=$(echo "$RENTAL" | jq -r .id)
echo "Rented: $(echo "$RENTAL" | jq -r .phone_number)"

# Poll every 5s for up to 2 minutes
for i in $(seq 1 24); do
  CODE=$(curl -s https://ohmyotp.com/api/v1/rentals/$RENTAL_ID/code \
    -H "Authorization: Bearer $API_KEY" | jq -r .code)
  if [ "$CODE" != "null" ] && [ -n "$CODE" ]; then
    echo "Got code: $CODE"
    exit 0
  fi
  sleep 5
done

# Timed out — cancel to get a refund
echo "No code arrived, cancelling..."
curl -s -X POST https://ohmyotp.com/api/v1/rentals/$RENTAL_ID/cancel \
  -H "Authorization: Bearer $API_KEY"

Errors

StatusMeaning
401Missing / invalid API key
402Insufficient balance
403Not the owner of this rental
404Resource not found (rental / service)
409No numbers available for this service
429Rate limited
502Upstream error