---
title: "Reconstitution math for one vial (paid)"
method: POST
path: "/v1/recon/calc"
---

# Reconstitution math for one vial (paid)

`POST /v1/recon/calc`

## Request

- Base URL: `https://api.doseplot.com`
- URL: `https://api.doseplot.com/v1/recon/calc`
- Auth: none declared

Given a vial mass, the volume you want to draw per dose, and a target dose, returns the concentration to reconstitute to and what one dose looks like on a syringe. Costs $0.01 per call over x402; an unpaid call answers 402 (see the 402 response). There is NO compound context here: validation is structural, and the unit is taken from the field name.

## Request body

- union: Exactly one target-dose field must be present. UNKNOWN FIELDS ARE REJECTED.
  - object
    - `vial_mg` number, required: Total mass in the vial, mg.
    - `draw_ml` number, required: The volume you want to DRAW for one dose, in mL -- not the vial fill. The fill needed to make that true comes back as bac_water_ml.
    - `target_dose_mg` number, required: Target dose, mg.
    - `target_dose_mcg` number: Target dose, mcg.
    - `frequency_days` number: Days between doses. Feeds days_per_vial only.
    - `cost_usd` number: Vial cost. Omitted, cost_per_dose_usd is null.
  - object
    - `vial_mg` number, required: Total mass in the vial, mg.
    - `draw_ml` number, required: The volume you want to DRAW for one dose, in mL -- not the vial fill. The fill needed to make that true comes back as bac_water_ml.
    - `target_dose_mg` number: Target dose, mg.
    - `target_dose_mcg` number, required: Target dose, mcg.
    - `frequency_days` number: Days between doses. Feeds days_per_vial only.
    - `cost_usd` number: Vial cost. Omitted, cost_per_dose_usd is null.

## Response `200`

The reconstitution plan.

- ReconCalcResponse
  - `disclaimer` string, required: Fixed disclaimer. Must be preserved when relaying any output to a human (terms clause 2).
  - `intended_use` string, required: Fixed intended-use statement. Must be preserved when relaying any output to a human.
  - `concentration_mg_per_ml` number, required: target dose / draw_ml. The concentration the vial must be reconstituted to.
  - `bac_water_ml` number, required: Bacteriostatic water to add to the vial, mL, so that draw_ml delivers the target dose.
  - `units_per_dose` number, required: draw_ml expressed in insulin-syringe units (U-100: 100 units per mL).
  - `syringe_marks` object, required: The draw read off a syringe, by syringe type.
    - `u100` number, required: Marks on a U-100 syringe.
  - `doses_per_vial` integer, required: Whole doses the vial yields. Partial doses are not counted.
  - `residual_mg` number, required: Mass left after the last whole dose.
  - `days_per_vial` number, required: doses_per_vial * frequency_days.
  - `cost_per_dose_usd` number, nullable, required: null when cost_usd was not supplied.
  - `meta` object, required
    - `frequency_days` number, required
    - `more` string, required: Pointer to the multi-compound planning app. Fixed literal; carries no request data.
    - `network_note` string: Which chain a paid call settles on, named in plain language. Absent when the deployment's network id is unrecognised.

## Other responses

- `400`: The request body is not a valid document for this endpoint (code: invalid_request), or the requested dose lies outside the compound's published dosing range (code: out_of_range), or a single dose is larger than the whole vial (code: dose_exceeds_vial). `detail` names one of THIS API's field names; it never echoes a submitted value, and an unknown field's name is not repeated back.
- `402`: Payment required. THE ONE RESPONSE ON THIS API THAT IS NOT problem+json and does NOT carry the disclaimer/intended_use envelope: it is the x402 challenge, and it carries no computed result. The payment-requirements document is base64-encoded in the PAYMENT-REQUIRED header; the body is an empty JSON object. The error-code vocabulary names this case `payment_required`, but no Problem body with that code is ever emitted.
- `405`: Method not allowed on a live path. The read endpoints are GET-only; the compute endpoints are POST-only.
- `429`: Rate limit exceeded (60 requests/minute on the read routes; 1000 /v1 reads/day; 300 requests/minute on the paid compute routes). Carries a Retry-After header. NOTE: a 429 raised by Cloudflare's own edge protection, rather than by this Worker, MAY be a non-JSON body (HTML) with no Retry-After -- treat ANY 429 as retryable regardless of content type, and do not assume the problem+json schema below.
- `500`: Unexpected internal error. Generic body; nothing about the request is echoed.
- `502`: The payment facilitator could not be reached or answered unusably (code: facilitator_unavailable). The request was NOT charged; retry is safe.
- `503`: This deployment has no payment rail configured (code: payments_unavailable). Never a silent free answer.

---

[API](https://skmtc.dev/doseplot/apis/doseplot-agent-api.md) · [All operations](https://skmtc.dev/doseplot/apis/doseplot-agent-api/llms.txt) · [OpenAPI document](https://skmtc.dev/doseplot/apis/doseplot-agent-api/revisions/f35133f7fbc1?raw)
