Campaigns
This page covers the per-campaign fields and rollout strategies inside the vaccination block. For the surrounding block structure and flows configuration, see the Overview.
Quick start
The fastest path is using the V-SEIHR model preset with a flat-count vaccination campaign. In the following example, we roll out vaccination starting in February 2025 with a target of 100,000 doses per day held constant across the window. See Dose allocation for how the daily dose count splits across age groups.
curl -X POST https://epyscenario-api.isi.it/api/v1/simulations \
-H "Content-Type: application/json" \
-d '{
"model": {
"preset": "V-SEIHR",
"parameters": {
"R0": 2.5,
"incubation_period": 3.0,
"infectious_period": 2.5,
"hosp_duration": 5.0,
"hosp_proportion": 0.05,
"VE_S": 0.7,
"VE_H": 0.85
}
},
"population": {"name": "United_States"},
"simulation": {"start_date": "2025-01-01", "end_date": "2025-06-30", "Nsim": 10},
"vaccination": {
"campaigns": [
{
"start_date": "2025-02-01",
"end_date": "2025-04-30",
"rollout": {"type": "flat_count", "daily_doses": 100000}
}
]
}
}'
The response includes the resulting Susceptible_to_Susceptible_vax transition series; see Inspecting the rollout for what to look at.
Campaign fields
Each entry in campaigns describes one rollout:
| Field | Required | Description |
|---|---|---|
name | no | Free-text label echoed back in metadata.vaccination. Handy for keeping multiple overlapping campaigns straight. |
start_date | yes | Campaign start (YYYY-MM-DD), inclusive. |
end_date | yes | Campaign end (YYYY-MM-DD), inclusive. Must be ≥ start_date. |
rollout | yes | Rollout strategy. v1 supports flat_count; the type field is the discriminator. See Rollout strategies. |
target_age_groups | no | List of age-group labels (e.g. ["50-64", "65+"]). Must be unique and must match labels from the resolved population. null (the default) means all groups. |
Rollout strategies
Flat rollout (count)
A constant daily_doses count is scheduled every day across the campaign window, distributed proportionally to the source-compartment population in each targeted age group.
"Flat" refers to the scheduled budget, not the delivered curve: as the source pool depletes (through vaccination, infections, etc.), the actual daily delivered count can drift below daily_doses. If the live pool drops below daily_doses per step, the per-source stochastic draw saturates against the available population; if the pool is empty, no doses are delivered that step. See the Dose allocation section for the per-step competing-risks draw.
| Field | Required | Description |
|---|---|---|
type | yes | Literal "flat_count". The discriminator. |
daily_doses | yes | Target doses delivered per day. Must be > 0. |
Example
Here is an example of V-SEIHR model run on a 1,000,000 homogeneous population (, , , 0.02% initial infections, no waning), with a single campaign scheduled at 5,000 doses/day from Feb 1 to Oct 15, 2025 (100 stochastic runs, median plotted).
The scheduled budget (dashed) holds at 5,000/day across the entire window, but the delivered count drops to zero around the end of May as is exhausted by the epidemic plus vaccination.
Custom-model usage
You can define a custom model that incorporates the effects of vaccination and takes advantage of the vaccination block. What you need is a model whose compartments include both a source and a vaccinated target, and (typically) a vaccinated layer that mirrors the unvaccinated transitions with vaccine-efficacy-attenuated rates. The block then drives doses across the source → target pairs declared in flows. You can model the effects of vaccination through transformed parameters (e.g. severity reduction) and additional transitions.
On a custom model the flows field is required; there is no default. Every source and (non-null) target must reference a compartment declared in model.compartments.
curl -X POST https://epyscenario-api.isi.it/api/v1/simulations \
-H "Content-Type: application/json" \
-d '{
"model": {
"compartments": ["S", "V", "I", "R"],
"parameters": {
"transmission_rate": 0.3,
"transmission_rate_v": "(1 - VE_S) * transmission_rate",
"VE_S": 0.7,
"recovery_rate": 0.1
},
"transitions": [
{"source": "S", "target": "I", "kind": "mediated", "params": ["transmission_rate", "I"]},
{"source": "V", "target": "I", "kind": "mediated", "params": ["transmission_rate_v", "I"]},
{"source": "I", "target": "R", "kind": "spontaneous", "params": ["recovery_rate"]}
]
},
"population": {"name": "Italy"},
"simulation": {"start_date": "2025-01-01", "end_date": "2025-06-30", "Nsim": 10},
"vaccination": {
"flows": [{"source": "S", "target": "V"}],
"campaigns": [
{
"start_date": "2025-02-01",
"end_date": "2025-03-31",
"rollout": {"type": "flat_count", "daily_doses": 50000}
}
]
}
}'
Multiple campaigns
Listing more than one campaign lets you stack rollouts. Two overlapping flat_count campaigns add their daily doses at every step. Use this for booster waves, prioritization changes (e.g. open eligibility on a given date by adding a younger-age campaign mid-rollout), or to compare a baseline campaign against an accelerated counterfactual.
curl -X POST https://epyscenario-api.isi.it/api/v1/simulations \
-H "Content-Type: application/json" \
-d '{
"model": {
"preset": "V-SEIHR",
"parameters": {"R0": 2.5, "VE_S": 0.7, "VE_H": 0.85}
},
"population": {
"name": "United_States",
"contacts_source": "prem_2021",
"age_group_mapping": {
"0-17": ["0-4", "5-9", "10-14", "15-19"],
"18-49": ["20-24", "25-29", "30-34", "35-39", "40-44", "45-49"],
"50-64": ["50-54", "55-59", "60-64"],
"65+": ["65-69", "70-74", "75+"]
}
},
"simulation": {"start_date": "2025-01-01", "end_date": "2025-06-30", "Nsim": 10},
"vaccination": {
"campaigns": [
{
"name": "phase 1 (older adults)",
"start_date": "2025-02-01",
"end_date": "2025-03-31",
"target_age_groups": ["65+"],
"rollout": {"type": "flat_count", "daily_doses": 40000}
},
{
"name": "phase 2 (open eligibility)",
"start_date": "2025-03-15",
"end_date": "2025-05-31",
"target_age_groups": ["18-49", "50-64", "65+"],
"rollout": {"type": "flat_count", "daily_doses": 80000}
}
]
}
}'