---
name: vapcal-tools
description: "Calculator URLs of VapCal with parameters, examples and limits."
metadata:
  profile: creabyte-ai-0.1
  updated: 2026-10-04
---

# VapCal tools

Updated: 2026-10-04 · Profile: creabyte-ai-0.1 · Overview for agents: https://www.vapcal.com/agents.md

Every calculator is a URL with parameters: GET only, no side effects, nothing is stored. The same URL returns the page for people and Markdown for agents: send `Accept: text/markdown`, use `/index.md?calc=…`, or add `format=md`. The Markdown lists the cleaned-up inputs, the result (the same texts as the page) and the share link to exactly this calculation.

An agent key with the scope `calc:run` runs the same calculation at `GET /api/agent/calc?kind=` plus the parameters, when the key's user has unlocked that calculator. Markdown by default, JSON with `Accept: application/json`. The share link is the public `/?calc=` URL and never contains the key. A key without `calc:run` gets 403. The call writes nothing (no audit row, no last-used update). Agent keys do not unlock calculators on page URLs.

JSON (`GET /api/calc?kind=` and `GET /api/agent/calc?kind=`) uses one shape: `kind`, `result`, `possible`. `possible` is false, with `result` null, when the mix cannot be made. For one release the old fields stay as deprecated aliases: `rows` on the mix chart (same as `result.rows`) and a top-level object named after the kind (same as `result`) on the others.

## Usage rules

- About 1 request per second, with bursts of up to 10.
- No bulk sweeps: do not iterate over parameter ranges or crawl result pages; ask for the calculation you need.
- Use conditional requests: send `If-None-Match` with the ETag (or `If-Modified-Since`); a 304 has no body.
- On 429, wait as long as `Retry-After` says before the next request.

## Answers

- 200: inputs, result, share link. Public calculators are cacheable (`Cache-Control: public`); answers for a logged-in account are `private`.
- 400: an invalid parameter; the answer names it and lists the allowed values (Markdown or HTML, as requested).
- 403: the calculator needs an account or a support level; a short unlock note (level, EUR threshold, links to https://www.vapcal.com/support and https://www.vapcal.com/login), no numbers. Also 403 when the calculators are switched off.
- 304: on `If-None-Match` / `If-Modified-Since` when nothing changed. Every answer has an ETag per format, `Last-Modified` and `Vary: Accept`.
- "n / a" in a result means the mix is not possible with these numbers; the answer says why.
- Language: English only (`lang` does not change the Markdown).

## Tools

| Tool | Purpose | Access |
|---|---|---|
| [single-mix](#single-mix) | Nicotine base and liquid amounts for one target strength. | public, free, no account |
| [mix-chart](#mix-chart) | Table of nicotine base and liquid amounts for ten target strengths. | public, free, no account |
| [shot-calculator](#shot-calculator) | How many nicotine shots a bottle needs. | account with support level Unlock (support from EUR 6) |
| [ohm-watt](#ohm-watt) | Ohm's law for a coil build. | account with support level Tools (support from EUR 15) |
| [coil-wraps](#coil-wraps) | Resistance of a single round-wire coil. | account with support level Tools (support from EUR 15) |
| [pgvg-adjust](#pgvg-adjust) | How much PG or VG to add to reach a target ratio. | account with support level Tools (support from EUR 15) |
| [dilute-boost](#dilute-boost) | Lower or raise the nicotine strength of an existing liquid. | account with support level Tools (support from EUR 15) |
| [batch-cost](#batch-cost) | PG, VG and nicotine amounts for a batch that hits a target total cost. | account with support level Lab (support from EUR 35) |

### single-mix

- **Name:** `single-mix` (Single mix), `calc=simple`
- **Purpose:** Nicotine base and liquid amounts for one target strength.
- **Method:** `GET https://www.vapcal.com/?calc=simple{&flask,aim,base}` (URI template; parameters in any order, all optional)
- **Parameters:**

| Name | Type | Unit | Range | Required | Default | Also accepted | Meaning |
|---|---|---|---|---|---|---|---|
| `flask` | number | ml | 0.1–100000 ml | optional | 30 | — | bottle size |
| `aim` | number | mg/ml | 0–1000 mg/ml | optional | 3 | — | target nicotine strength |
| `base` | number | mg/ml | 0.1–1000 mg/ml | optional | 36 | — | nicotine base strength |

- **Example request:** `GET https://www.vapcal.com/index.md?calc=simple&flask=30&aim=3&base=36`
- **Example response:** (shortened: result and share link)

````markdown
## Result

| Result | Value |
|---|---|
| Nicotine base | 2.5 ml |
| Liquid | 27.5 ml |

## Share link

- Page: https://www.vapcal.com/?calc=simple&flask=30&aim=3&base=36
- Markdown: https://www.vapcal.com/index.md?calc=simple&flask=30&aim=3&base=36
````

- **Response formats:** HTML (the page, same URL without `format=md`); Markdown via `Accept: text/markdown`, `/index.md?calc=simple&…` or `format=md`; JSON via `GET https://www.vapcal.com/api/calc?kind=simple&…` (same parameters, send no `Authorization` header).
- **Auth:** none (public).
- **Side effects:** none (GET only, nothing is stored).
- **Limits:** Usage rules above (about 1 request per second, bursts up to 10). Values outside the ranges answer 400 with the allowed ranges. Precision: `nicotine_ml` 1 dp, `liquid_ml` 1 dp; the Markdown shows the same rounded texts as the page.

### mix-chart

- **Name:** `mix-chart` (Mix chart), `calc=chart`
- **Purpose:** Table of nicotine base and liquid amounts for ten target strengths.
- **Method:** `GET https://www.vapcal.com/?calc=chart{&flask,base,start,steps}` (URI template; parameters in any order, all optional)
- **Parameters:**

| Name | Type | Unit | Range | Required | Default | Also accepted | Meaning |
|---|---|---|---|---|---|---|---|
| `flask` | number | ml | 0.1–100000 ml | optional | 10 | — | bottle size |
| `base` | number | mg/ml | 0.1–1000 mg/ml | optional | 36 | — | nicotine base strength ("bunker") |
| `start` | integer | mg/ml | 0–10 mg/ml | optional | 0 | — | first strength in the table |
| `steps` | integer | mg/ml | 1–10 mg/ml | optional | 1 | — | increase per row |

- **Example request:** `GET https://www.vapcal.com/index.md?calc=chart&flask=10&base=4&start=0&steps=1`
- **Example response:** (shortened: result and share link)

````markdown
## Result

| Strength | Nicotine base | Liquid |
|---|---|---|
| 0 mg/ml | 0 ml | 10 ml |
| 1 mg/ml | 2.5 ml | 7.5 ml |
| 2 mg/ml | 5 ml | 5 ml |
| 3 mg/ml | 7.5 ml | 2.5 ml |
| 4 mg/ml | 10 ml | 0 ml |
| 5 mg/ml | n / a | n / a |
| 6 mg/ml | n / a | n / a |
| 7 mg/ml | n / a | n / a |
| 8 mg/ml | n / a | n / a |
| 9 mg/ml | n / a | n / a |

## Share link

- Page: https://www.vapcal.com/?calc=chart&flask=10&base=4&start=0&steps=1
- Markdown: https://www.vapcal.com/index.md?calc=chart&flask=10&base=4&start=0&steps=1
````

- **Response formats:** HTML (the page, same URL without `format=md`); Markdown via `Accept: text/markdown`, `/index.md?calc=chart&…` or `format=md`; JSON via `GET https://www.vapcal.com/api/calc?kind=chart&…` (same parameters, send no `Authorization` header).
- **Auth:** none (public).
- **Side effects:** none (GET only, nothing is stored).
- **Limits:** Usage rules above (about 1 request per second, bursts up to 10). Values outside the ranges answer 400 with the allowed ranges. Precision: `rows[].strength` 0 dp, `rows[].nicotine_ml` 1 dp, `rows[].liquid_ml` 1 dp; the Markdown shows the same rounded texts as the page.

### shot-calculator

- **Name:** `shot-calculator` (Shot calculator), `calc=shots`
- **Purpose:** How many nicotine shots a bottle needs.
- **Method:** `GET https://www.vapcal.com/?calc=shots{&flask,aim,base,shots}` (URI template; parameters in any order, all optional)
- **Parameters:**

| Name | Type | Unit | Range | Required | Default | Also accepted | Meaning |
|---|---|---|---|---|---|---|---|
| `flask` | number | ml | 0.1–100000 ml | optional | 60 | — | bottle size |
| `aim` | number | mg/ml | 0–1000 mg/ml | optional | 3 | — | target nicotine strength |
| `base` | number | mg/ml | 0.1–1000 mg/ml | optional | 20 | `shot_mg` | shot strength |
| `shots` | number | ml | 0.1–1000 ml | optional | 10 | `shot_ml` | shot size |

- **Example request:** `GET https://www.vapcal.com/index.md?calc=shots&flask=60&aim=3&base=20&shots=10`
- **Example response:** (shortened: result and share link)

````markdown
## Result

| Result | Value |
|---|---|
| Shots | 0.9 |
| Nicotine shots (volume) | 9 ml |
| Liquid | 51 ml |

## Share link

- Page: https://www.vapcal.com/?calc=shots&flask=60&aim=3&base=20&shots=10
- Markdown: https://www.vapcal.com/index.md?calc=shots&flask=60&aim=3&base=20&shots=10
````

- **Response formats:** HTML (the page, same URL without `format=md`); Markdown via `Accept: text/markdown`, `/index.md?calc=shots&…` or `format=md`; JSON via `GET https://www.vapcal.com/api/calc?kind=shots&…` (same parameters, send no `Authorization` header).
- **Auth:** a logged-in browser session of an account with support level Unlock (support from EUR 6). Without it the URL answers 403 with a short unlock note and no numbers.
- **Side effects:** none (GET only, nothing is stored).
- **Limits:** Usage rules above (about 1 request per second, bursts up to 10). Values outside the ranges answer 400 with the allowed ranges. Precision: `shots` 2 dp, `nicotine_ml` 1 dp, `liquid_ml` 1 dp; the Markdown shows the same rounded texts as the page.

### ohm-watt

- **Name:** `ohm-watt` (Ohm / watt), `calc=coil`
- **Purpose:** Ohm's law for a coil build.
- **Method:** `GET https://www.vapcal.com/?calc=coil{&ohms,watts}` (URI template; parameters in any order, all optional)
- **Parameters:**

| Name | Type | Unit | Range | Required | Default | Also accepted | Meaning |
|---|---|---|---|---|---|---|---|
| `ohms` | number | ohm | 0.01–10 ohm | optional | 0.30 | — | coil resistance |
| `watts` | number | W | 0–1000 W | optional | 40 | — | power |

- **Example request:** `GET https://www.vapcal.com/index.md?calc=coil&ohms=0.30&watts=40`
- **Example response:** (shortened: result and share link)

````markdown
## Result

| Result | Value |
|---|---|
| Voltage | 3.46 V |
| Current | 11.55 A |

## Share link

- Page: https://www.vapcal.com/?calc=coil&ohms=0.30&watts=40
- Markdown: https://www.vapcal.com/index.md?calc=coil&ohms=0.30&watts=40
````

- **Response formats:** HTML (the page, same URL without `format=md`); Markdown via `Accept: text/markdown`, `/index.md?calc=coil&…` or `format=md`; JSON via `GET https://www.vapcal.com/api/calc?kind=coil&…` (same parameters, send no `Authorization` header).
- **Auth:** a logged-in browser session of an account with support level Tools (support from EUR 15). Without it the URL answers 403 with a short unlock note and no numbers.
- **Side effects:** none (GET only, nothing is stored).
- **Limits:** Usage rules above (about 1 request per second, bursts up to 10). Values outside the ranges answer 400 with the allowed ranges. Precision: `volts` 2 dp, `amps` 2 dp, `ohms` 3 dp, `watts` 1 dp; the Markdown shows the same rounded texts as the page.

### coil-wraps

- **Name:** `coil-wraps` (Coil wraps), `calc=wraps`
- **Purpose:** Resistance of a single round-wire coil.
- **Method:** `GET https://www.vapcal.com/?calc=wraps{&rho,awg,id,wraps}` (URI template; parameters in any order, all optional)
- **Parameters:**

| Name | Type | Unit | Range | Required | Default | Also accepted | Meaning |
|---|---|---|---|---|---|---|---|
| `rho` | number | ohm mm²/m | 0.01–5 ohm mm²/m | optional | 1.45 | — | wire resistivity (Kanthal A1 1.45, Ni80 1.09, SS316L 0.75) |
| `awg` | enum | AWG | 20 · 22 · 24 · 26 · 28 · 30 · 32 | optional | 26 | — | wire gauge from the wire table |
| `id` | number | mm | 0.1–20 mm | optional | 2.5 | — | inner coil diameter |
| `wraps` | number | wraps | 1–100 wraps | optional | 6 | — | number of wraps |

- **Example request:** `GET https://www.vapcal.com/index.md?calc=wraps&rho=1.45&awg=26&id=2.5&wraps=6`
- **Example response:** (shortened: result and share link)

````markdown
## Result

| Result | Value |
|---|---|
| Coil resistance | 0.616 Ω |
| Wire length | 54.8 mm |

## Share link

- Page: https://www.vapcal.com/?calc=wraps&rho=1.45&awg=26&id=2.5&wraps=6
- Markdown: https://www.vapcal.com/index.md?calc=wraps&rho=1.45&awg=26&id=2.5&wraps=6
````

- **Response formats:** HTML (the page, same URL without `format=md`); Markdown via `Accept: text/markdown`, `/index.md?calc=wraps&…` or `format=md`; JSON via `GET https://www.vapcal.com/api/calc?kind=wraps&…` (same parameters, send no `Authorization` header).
- **Auth:** a logged-in browser session of an account with support level Tools (support from EUR 15). Without it the URL answers 403 with a short unlock note and no numbers.
- **Side effects:** none (GET only, nothing is stored).
- **Limits:** Usage rules above (about 1 request per second, bursts up to 10). Values outside the ranges answer 400 with the allowed ranges. Precision: `ohms` 3 dp, `length_mm` 1 dp, `wire_mm` 3 dp; the Markdown shows the same rounded texts as the page.

### pgvg-adjust

- **Name:** `pgvg-adjust` (PG/VG adjust), `calc=pgvg`
- **Purpose:** How much PG or VG to add to reach a target ratio.
- **Method:** `GET https://www.vapcal.com/?calc=pgvg{&flask,cur_vg,cur_pg,cur_nic,mode,target}` (URI template; parameters in any order, all optional)
- **Parameters:**

| Name | Type | Unit | Range | Required | Default | Also accepted | Meaning |
|---|---|---|---|---|---|---|---|
| `flask` | number | ml | 0.1–100000 ml | optional | 60 | — | bottle size |
| `cur_vg` | number | % | 0–100 % | optional | 70 | — | current VG share |
| `cur_pg` | number | % | 0–100 % | optional | 30 | — | current PG share; cur\_vg + cur\_pg = 100 |
| `cur_nic` | number | mg/ml | 0–1000 mg/ml | optional | 6 | — | current nicotine strength |
| `mode` | enum | — | vg · pg | optional | vg | — | which share the target sets |
| `target` | number | % | 0–100 % | optional | 50 | — | target share of the chosen mode (legacy: target\_vg, target\_pg) |

Rule: `cur_vg` + `cur_pg` = 100. When only one is given, the other is 100 minus it (same for `pg_pct`/`vg_pct` in batch cost). `target_vg` or `target_pg` set `mode` and `target`.

- **Example request:** `GET https://www.vapcal.com/index.md?calc=pgvg&flask=60&cur_vg=70&cur_pg=30&cur_nic=6&mode=vg&target=50`
- **Example response:** (shortened: result and share link)

````markdown
## Result

| Result | Value |
|---|---|
| Add | 24 ml PG |
| New bottle | 84 ml |
| New nicotine strength | 4.29 mg/ml |
| VG/PG | 50% VG / 50% PG |

## Share link

- Page: https://www.vapcal.com/?calc=pgvg&flask=60&cur_vg=70&cur_pg=30&cur_nic=6&mode=vg&target=50
- Markdown: https://www.vapcal.com/index.md?calc=pgvg&flask=60&cur_vg=70&cur_pg=30&cur_nic=6&mode=vg&target=50
````

- **Response formats:** HTML (the page, same URL without `format=md`); Markdown via `Accept: text/markdown`, `/index.md?calc=pgvg&…` or `format=md`; JSON via `GET https://www.vapcal.com/api/calc?kind=pgvg&…` (same parameters, send no `Authorization` header).
- **Auth:** a logged-in browser session of an account with support level Tools (support from EUR 15). Without it the URL answers 403 with a short unlock note and no numbers.
- **Side effects:** none (GET only, nothing is stored).
- **Limits:** Usage rules above (about 1 request per second, bursts up to 10). Values outside the ranges answer 400 with the allowed ranges. Precision: `add_ml` 1 dp, `new_ml` 1 dp, `new_nic` 2 dp, `new_vg_pct` 1 dp, `new_pg_pct` 1 dp; the Markdown shows the same rounded texts as the page.

### dilute-boost

- **Name:** `dilute-boost` (Dilute / boost), `calc=dilute`
- **Purpose:** Lower or raise the nicotine strength of an existing liquid.
- **Method:** `GET https://www.vapcal.com/?calc=dilute{&ml,from,to,boost}` (URI template; parameters in any order, all optional)
- **Parameters:**

| Name | Type | Unit | Range | Required | Default | Also accepted | Meaning |
|---|---|---|---|---|---|---|---|
| `ml` | number | ml | 0.1–100000 ml | optional | 30 | — | current amount |
| `from` | number | mg/ml | 0–1000 mg/ml | optional | 6 | — | current strength |
| `to` | number | mg/ml | 0–1000 mg/ml | optional | 3 | — | target strength |
| `boost` | number | mg/ml | 0–1000 mg/ml | optional | 20 | — | booster strength (only used when raising) |

- **Example request:** `GET https://www.vapcal.com/index.md?calc=dilute&ml=30&from=6&to=3&boost=20`
- **Example response:** (shortened: result and share link)

````markdown
## Result

| Result | Value |
|---|---|
| Kind | Dilute |
| Add | 30 ml zero-nic |
| New bottle | 60 ml |

## Share link

- Page: https://www.vapcal.com/?calc=dilute&ml=30&from=6&to=3&boost=20
- Markdown: https://www.vapcal.com/index.md?calc=dilute&ml=30&from=6&to=3&boost=20
````

- **Response formats:** HTML (the page, same URL without `format=md`); Markdown via `Accept: text/markdown`, `/index.md?calc=dilute&…` or `format=md`; JSON via `GET https://www.vapcal.com/api/calc?kind=dilute&…` (same parameters, send no `Authorization` header).
- **Auth:** a logged-in browser session of an account with support level Tools (support from EUR 15). Without it the URL answers 403 with a short unlock note and no numbers.
- **Side effects:** none (GET only, nothing is stored).
- **Limits:** Usage rules above (about 1 request per second, bursts up to 10). Values outside the ranges answer 400 with the allowed ranges. Precision: `add_ml` 1 dp, `new_ml` 1 dp; the Markdown shows the same rounded texts as the page.

### batch-cost

- **Name:** `batch-cost` (Batch cost), `calc=cost`
- **Purpose:** PG, VG and nicotine amounts for a batch that hits a target total cost.
- **Method:** `GET https://www.vapcal.com/?calc=cost{&batch,pg_pct,vg_pct,target_cost,vg_price,vg_bottle,pg_price,pg_bottle,nic_price,nic_bottle,nic_str,currency}` (URI template; parameters in any order, all optional)
- **Parameters:**

| Name | Type | Unit | Range | Required | Default | Also accepted | Meaning |
|---|---|---|---|---|---|---|---|
| `batch` | number | ml | 0–100000 ml | optional | 10 | — | batch volume |
| `pg_pct` | number | % | 0–100 % | optional | 30 | — | PG share of the nicotine-free part |
| `vg_pct` | number | % | 0–100 % | optional | 70 | — | VG share of the nicotine-free part |
| `target_cost` | number | currency | 0–1000000 | optional | 2.00 | `zielwert` (deprecated), `aim` (deprecated) | target total cost of the batch. zielwert and aim are deprecated names for this field; elsewhere aim is the nicotine strength |
| `vg_price` | number | currency | 0–1000000 | optional | 20.00 | — | VG stock price |
| `vg_bottle` | number | ml | 0–1000000 ml | optional | 1000 | — | VG stock bottle size |
| `pg_price` | number | currency | 0–1000000 | optional | 20.00 | — | PG stock price |
| `pg_bottle` | number | ml | 0–1000000 ml | optional | 1000 | — | PG stock bottle size |
| `nic_price` | number | currency | 0–1000000 | optional | 35.00 | — | nicotine base stock price |
| `nic_bottle` | number | ml | 0–1000000 ml | optional | 100 | — | nicotine base stock bottle size |
| `nic_str` | number | mg/ml | 0–1000 mg/ml | optional | 20 | — | nicotine base strength |
| `currency` | enum | — | CHF · EUR · USD · GBP · JPY · AED · AFN · ALL · AMD · ANG · AOA · ARS · AUD · AWG · AZN · BAM · BBD · BDT · BGN · BHD · BIF · BMD · BND · BOB · BRL · BSD · BTN · BWP · BYN · BZD · CAD · CDF · CLP · CNY · COP · CRC · CUP · CVE · CZK · DJF · DKK · DOP · DZD · EGP · ERN · ETB · FJD · FKP · GEL · GHS · GIP · GMD · GNF · GTQ · GYD · HKD · HNL · HTG · HUF · IDR · ILS · INR · IQD · IRR · ISK · JMD · JOD · KES · KGS · KHR · KMF · KRW · KWD · KYD · KZT · LAK · LBP · LKR · LRD · LSL · LYD · MAD · MDL · MGA · MKD · MMK · MNT · MOP · MRU · MUR · MVR · MWK · MXN · MYR · MZN · NAD · NGN · NIO · NOK · NPR · NZD · OMR · PAB · PEN · PGK · PHP · PKR · PLN · PYG · QAR · RON · RSD · RUB · RWF · SAR · SBD · SCR · SDG · SEK · SGD · SHP · SLE · SOS · SRD · SSP · STN · SYP · SZL · THB · TJS · TMT · TND · TOP · TRY · TTD · TWD · TZS · UAH · UGX · UYU · UZS · VES · VND · VUV · WST · XAF · XCD · XOF · XPF · YER · ZAR · ZMW | optional | CHF | — | display label only, no conversion |

Rule: when only one of `pg_pct`/`vg_pct` is given, the other is 100 minus it.

- **Example request:** `GET https://www.vapcal.com/index.md?calc=cost&batch=10&pg_pct=30&vg_pct=70&target_cost=2.00&vg_price=20.00&vg_bottle=1000&pg_price=20.00&pg_bottle=1000&nic_price=35.00&nic_bottle=100&nic_str=20&currency=CHF`
- **Example response:** (shortened: result and share link)

````markdown
## Result

| Result | Value |
|---|---|
| Total | 2.00 CHF |
| Per ml | 0.200 CHF/ml |
| Nicotine strength | 10.9 mg/ml |
| VG | 3.19 ml · 0.06 CHF |
| PG | 1.36 ml · 0.03 CHF |
| Nicotine base | 5.45 ml · 1.91 CHF |

## Share link

- Page: https://www.vapcal.com/?calc=cost&batch=10&pg_pct=30&vg_pct=70&target_cost=2.00&vg_price=20.00&vg_bottle=1000&pg_price=20.00&pg_bottle=1000&nic_price=35.00&nic_bottle=100&nic_str=20&currency=CHF
- Markdown: https://www.vapcal.com/index.md?calc=cost&batch=10&pg_pct=30&vg_pct=70&target_cost=2.00&vg_price=20.00&vg_bottle=1000&pg_price=20.00&pg_bottle=1000&nic_price=35.00&nic_bottle=100&nic_str=20&currency=CHF
````

- **Response formats:** HTML (the page, same URL without `format=md`); Markdown via `Accept: text/markdown`, `/index.md?calc=cost&…` or `format=md`; JSON via `GET https://www.vapcal.com/api/calc?kind=cost&…` (same parameters, send no `Authorization` header).
- **Auth:** a logged-in browser session of an account with support level Lab (support from EUR 35). Without it the URL answers 403 with a short unlock note and no numbers.
- **Side effects:** none (GET only, nothing is stored).
- **Limits:** Usage rules above (about 1 request per second, bursts up to 10). Values outside the ranges answer 400 with the allowed ranges. Precision: `total` 2 dp, `per_ml` 3 dp, `vg_ml` 2 dp, `pg_ml` 2 dp, `nicotine_ml` 2 dp, `nic_target` 2 dp, `cost_vg` 2 dp, `cost_pg` 2 dp, `cost_nic` 2 dp; the Markdown shows the same rounded texts as the page.
