---
title: "Simulate a serum curve (paid)"
method: POST
path: "/v1/simulate"
---

# Simulate a serum curve (paid)

`POST /v1/simulate`

## Request

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

Walks the pharmacokinetic model for ONE compound at one dose and cadence and returns the serum curve. Costs $0.01 per call over x402; an unpaid call answers 402 (see the 402 response). The dose is validated against the compound's PUBLISHED dosing range, in the compound's own unit and period, using the cadence you send -- so a range published per week is compared against dose * injections_per_week.

## Request body

- union: Exactly one dose field must be present. UNKNOWN FIELDS ARE REJECTED: a misspelling is a structural failure (400 when a payment is presented; the 402 challenge when none is), not a silently ignored key (a dropped `injections_per_week` would change the answer). The dose is converted to mg ONCE and the converted value is what both the range check and the model use.
  - object
    - `compound` string, required: Canon id, slug, or alias. Slug and alias matching is case-insensitive.
    - `dose_mg` number, required: Dose per injection, milligrams.
    - `dose_mcg` number: Dose per injection, micrograms.
    - `dose_iu` number: Dose per injection in the compound's activity unit. Requires a published conversion for that compound, else 422 unit_unsupported_for_compound.
    - `injections_per_week` number, required: Injections per WEEK -- not per day. The name is the contract: a per-day reading of the same number changes the accepted dose range by 7x.
    - `duration_weeks` integer, required: Length of the dosing window. The model always adds a 60-day washout tail.
    - `route` string: One of the compound's published routes (see /v1/compounds/{idOrSlug}); a string this compound does not publish is 422 route_unsupported_for_compound. Omitted, the compound's primary route is used.
    - `samples_per_day` integer: Sample resolution of the returned series.
  - object
    - `compound` string, required: Canon id, slug, or alias. Slug and alias matching is case-insensitive.
    - `dose_mg` number: Dose per injection, milligrams.
    - `dose_mcg` number, required: Dose per injection, micrograms.
    - `dose_iu` number: Dose per injection in the compound's activity unit. Requires a published conversion for that compound, else 422 unit_unsupported_for_compound.
    - `injections_per_week` number, required: Injections per WEEK -- not per day. The name is the contract: a per-day reading of the same number changes the accepted dose range by 7x.
    - `duration_weeks` integer, required: Length of the dosing window. The model always adds a 60-day washout tail.
    - `route` string: One of the compound's published routes (see /v1/compounds/{idOrSlug}); a string this compound does not publish is 422 route_unsupported_for_compound. Omitted, the compound's primary route is used.
    - `samples_per_day` integer: Sample resolution of the returned series.
  - object
    - `compound` string, required: Canon id, slug, or alias. Slug and alias matching is case-insensitive.
    - `dose_mg` number: Dose per injection, milligrams.
    - `dose_mcg` number: Dose per injection, micrograms.
    - `dose_iu` number, required: Dose per injection in the compound's activity unit. Requires a published conversion for that compound, else 422 unit_unsupported_for_compound.
    - `injections_per_week` number, required: Injections per WEEK -- not per day. The name is the contract: a per-day reading of the same number changes the accepted dose range by 7x.
    - `duration_weeks` integer, required: Length of the dosing window. The model always adds a 60-day washout tail.
    - `route` string: One of the compound's published routes (see /v1/compounds/{idOrSlug}); a string this compound does not publish is 422 route_unsupported_for_compound. Omitted, the compound's primary route is used.
    - `samples_per_day` integer: Sample resolution of the returned series.

## Response `200`

The modelled serum curve.

- SimulateResponse
  - `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.
  - `compound` object, required
    - `id` integer, required
    - `slug` string, required
    - `name` string, required
  - `series` object[], required: One point per sample, covering duration_weeks * 7 + 60 days at samples_per_day resolution.
    - `day` number, required: Cycle day, 1-indexed: the first sample is day 1.0.
    - `level` number, required: Modelled serum level at that sample, in `units`.
  - `units` 'ng/dL' | 'mcg' | 'mg', required: The display identity of `level` for this compound, resolved by the model, and the ONLY correct label for those numbers. ng/dL for anchored androgens (the curve is scaled to a per-molecule serum anchor); mcg for injectable peptides; mg otherwise (the raw model output).
  - `meta` object, required
    - `samples_per_day` integer, required
    - `duration_weeks` integer, required
    - `injections_per_week` number, required: Echoed back as REQUESTED. Above 7 injections/week the model quantizes the cadence to whole doses per day; this field is what you asked for, not what the walk did.
    - `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.
- `404`: No published compound matches the submitted identifier (code: unknown_compound).
- `405`: Method not allowed on a live path. The read endpoints are GET-only; the compute endpoints are POST-only.
- `422`: The request is well-formed but cannot be checked against the published data: the compound's dosing range is free text this API refuses to guess at (code: dosing_unvalidatable), the compound has no published conversion for the unit the request used (code: unit_unsupported_for_compound), or the compound does not publish the administration route the request named (code: route_unsupported_for_compound). All three are deterministic refusals, not transient failures; retrying the same body returns the same code. None is a schema failure -- the legal values are per-compound, so read /v1/compounds/{idOrSlug} rather than the request schema.
- `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)
