AnvilJSON utilities

Anvil › Docs › /v1/battery

Power bank calculator API: real charges, mAh to Wh, flight rule, gadget plan

A 10,000 mAh power bank does not give a 5,000 mAh phone two charges. The bank's mAh are counted at 3.7 V, phones are about 3.85 V, and roughly a third of the energy turns into heat on the way. This endpoint does that maths properly, and can check a whole list of gadgets against one bank.

In one line: GET /v1/battery?capacity=10000&device=phone&want=3&charger_w=20 returns JSON. No key, CORS on, 60 requests a minute.
GET

/v1/battery

Power bank maths: charges after losses, size needed, flight rule, multi-gadget plan. Change the values and press Send request to call the live API.

Parameters

NameTypeWhat it doesDefault
modestringcharges (default) | plan | devicescharges
capacity requiredstringPower bank capacity (mAh unless unit=wh)—
unitstringmah or whmah
voltsnumberCell voltage the mAh is rated at3.7
efficiencynumberPercent of the bank's energy that reaches the gadget (10-100)65
devicestringPreset gadget (mode=charges): phone, phone_s, phone_l, tablet, watch, buds, ereader, torch, speaker, console, laptop, laptop_lphone
device_whnumberCustom device battery in Wh (overrides device)—
device_mahnumberCustom device battery in mAh (with device_volts, default 3.85)—
healthnumberDevice battery health percent (20-100)100
fromnumberDevice starts at this percent0
tonumberCharge the device to this percent100
wantnumberHow many charges you want: returns the bank size needed—
charger_wnumberWall charger watts: returns rough refill hours—
planstringmode=plan: gadget.count.from.to joined by _ (up to 12)—
orderstringmode=plan: list (first gets charged first) or share (same fraction each)list

Example

Request:

GET https://api.oddlathe.com/v1/battery?capacity=10000&device=phone&want=3&charger_w=20

Response (generated by the real code when these docs were last built; random or time-based values will differ for you):

{
 "mode": "charges",
 "bank": {
  "wh": 37,
  "mah": 10000,
  "volts": 3.7,
  "mah_at_usb_5v": 7400
 },
 "device": {
  "key": "phone",
  "label": "Typical phone",
  "wh": 17.3,
  "health_percent": 100,
  "from_percent": 0,
  "to_percent": 100
 },
 "efficiency_percent": 65,
 "usable_wh": 24.05,
 "lost_as_heat_wh": 12.95,
 "per_charge_wh": 17.3,
 "charges": 1.39,
 "full_charges": 1,
 "flight": {
  "level": "ok",
  "rule": "100 Wh or less",
  "text": "Carry-on only: fine in hand luggage on most airlines. Never in checked bags."
 },
 "summary": "A 10000 mAh (37 Wh) bank gives about 1.4 charges of a typical phone (0% to 100%) at 65% efficiency.",
 "size_for_want": {
  "charges": 3,
  "wh": 79.85,
  "mah_at_3_7v": 22000,
  "flight": {
   "level": "ok",
   "rule": "100 Wh or less",
   "text": "Carry-on only: fine in hand luggage on most airlines. Never in checked bags."
  }
 },
 "refill_hours": 2.39
}

Code examples

curl
curl 'https://api.oddlathe.com/v1/battery?capacity=10000&device=phone&want=3&charger_w=20'
JavaScript (browser or Node 18+)
const params = new URLSearchParams({
  capacity: "10000",
  device: "phone",
  want: "3",
  charger_w: "20"
});
const res = await fetch(`https://api.oddlathe.com/v1/battery?${params}`);
if (!res.ok) throw new Error((await res.json()).error.message);
const data = await res.json();
console.log(data);
Python (standard library only)
import json, urllib.parse, urllib.request

params = urllib.parse.urlencode({"capacity": "10000", "device": "phone", "want": "3", "charger_w": "20"})
url = "https://api.oddlathe.com/v1/battery?" + params
# Send a User-Agent: the edge network refuses Python's default one.
req = urllib.request.Request(url, headers={"User-Agent": "my-script/1.0"})
with urllib.request.urlopen(req, timeout=10) as r:
    data = json.load(r)
print(data)

When it's useful

  • Product pages and comparison tables that show realistic charges instead of label maths
  • Trip and festival packing apps: will one bank last two phones and a torch?
  • Checking a bank against the airline 100 Wh and 160 Wh limits
  • Teaching why mAh numbers from different devices aren't comparable

Good to know

  • mode=charges (default) needs capacity. Pick a preset device or pass device_wh or device_mah. Returns charges, usable_wh, lost_as_heat_wh, per_charge_wh, bank.mah_at_usb_5v and flight.
  • Add want=3 for size_for_want (Wh and a rounded mAh at 3.7 V), and charger_w=20 for refill_hours (about 85% charging efficiency plus a slow final stretch).
  • mode=plan takes plan=phone.2.20.100_tablet.1.10.100: each gadget is key.count.from.to, up to 12 joined by _. order=list charges the first gadget first; order=share gives every gadget the same fraction. Returns each gadget's ends_at_percent, lasts, runs_out_on, gets_nothing, left_percent and bank_needed.
  • mode=devices lists the preset gadgets and their typical battery sizes. Real devices vary, so pass device_wh when you know it.
  • The default efficiency of 65% is a realistic middle for phone charging over USB; good USB-C PD banks reach about 75-85%, cheap banks and wireless charging less.
  • Browser UI: Tooltern power bank calculator with the same model and a sleepover or trip planner (nothing leaves your device).

How many real charges a power bank gives once conversion losses (about a third, as heat) are counted. mAh is converted to Wh at the cell voltage, so bank and phone numbers become comparable. Also returns the bank size for N charges, the airline 100 Wh / 160 Wh rule and a rough refill time. mode=plan checks a whole list of gadgets from one bank (in list order or shared evenly) and says which one it runs out on and what size bank the list needs. Pure maths; nothing is stored.

Errors

Errors are JSON like {"error": {"code": "…", "message": "…"}}. The ones this endpoint can return:

  • missing_param (400): a required parameter is missing or empty
  • bad_param (400): a value is the wrong type or out of range (the message says which)
  • rate_limited (429): over 60 requests a minute; wait for Retry-After seconds

Questions

How many charges does a 10,000 mAh power bank give?

About 1.4 full charges of a typical 17 Wh phone. <code>/v1/battery?capacity=10000&amp;device=phone</code> returns 1.39: 37 Wh stored, about 24 Wh reaches the phone at 65% efficiency.

Why isn't it 10,000 ÷ 4,500 = 2.2?

The bank's mAh are at 3.7 V and the phone's at about 3.85 V, and the voltage boost to 5 V or more plus the phone's own charging circuit lose around a third as heat. Converting to watt-hours makes the numbers comparable.

Can I fly with a 20,000 mAh power bank?

Usually yes in hand luggage: 20,000 mAh at 3.7 V is 74 Wh, under the 100 Wh limit. Between 100 and 160 Wh needs airline approval; over 160 Wh is not allowed. Never in checked bags.

Is anything stored?

Never. Pure maths on the query string.

Related endpoints

Prefer a page to an API?

Published · OpenAPI 3.1 spec · Limits and privacy