Template gallery / weekly-schedule

Weekly training schedule template

One week on one sheet for the client: the week's focus knocked out of a black bar with the week's targets beside it, then seven ruled day rows with a box to tick, a time, a duration and an intensity per session, the key session in red, reminders numbered, and ruled lines to write the week up on. A day with no session is drawn as a tinted rest row rather than left out.

chromium default PDF 11 top-level fields Billed per page

Rendered preview of the weekly-schedule template
Rendered by Galley from the example payload below, at 816px wide , scale 2.

Fields

The full JSON Schema is below. Required fields are marked; anything missing comes back as a 422 naming the path, the expected type and a value that would be accepted.

Field Type Required Description
accent string optional The one hot accent: the key-session title, the block name and the reminder numerals. A hex colour or a CSS colour keyword. It is interpolated into the stylesheet, so nothing else is accepted.
title string optional
client object { name } required
coach object { name, business, email, logo_url } optional
week object { starting, ending, number, of, … } required
targets array of object { label, value, note } optional The figures knocked out of the black bar beside the focus. Four is the most that fits comfortably.
days array of object { day, date, summary, rest_label, … } required One block per day. A day with no `sessions` is drawn as a rest day.
reminders_heading string optional
reminders array of string optional
log object { heading, prompt, lines } optional Ruled lines for the athlete to write on, for the people who print this and stick it on the fridge.
footer string optional Replaces the default tick-the-box line.

Default render options

Applied unless you override them. Options are part of the cache key.

page_size "Letter"
margin "0.5in"
print_background true

Example payload

This exact object renders the preview above. It is also what the API echoes back in a validation error, so an agent can repair a payload without a round trip to the docs.

example.jsonjson
{
  "title": "This week",
  "client": {
    "name": "Nadia Ferreira-Blake"
  },
  "coach": {
    "name": "Owen Castellanos",
    "business": "Northbank Endurance",
    "email": "owen@northbankendurance.test"
  },
  "week": {
    "starting": "2026-11-02",
    "ending": "2026-11-08",
    "number": 7,
    "of": 12,
    "phase": "Build",
    "focus": "The biggest week of the block. Saturday's long run has four miles of race pace at the end of it, and that is the session that matters — everything else this week exists to get you to Saturday able to run it."
  },
  "targets": [
    {
      "label": "Volume",
      "value": "37 mi",
      "note": "Up 3 on last week"
    },
    {
      "label": "Quality",
      "value": "2",
      "note": "Wednesday and Saturday"
    },
    {
      "label": "Time on feet",
      "value": "5h 40m",
      "note": "Approximate"
    },
    {
      "label": "Strength",
      "value": "1",
      "note": "Monday, 30 min"
    }
  ],
  "days": [
    {
      "day": "Monday",
      "date": "2026-11-02",
      "summary": "Strength only",
      "sessions": [
        {
          "time": "Evening",
          "title": "Strength",
          "detail": "Goblet squat 3 x 8, Romanian deadlift 3 x 8, split squat 3 x 8 each side, calf raise 3 x 15, side plank 3 x 30s each side",
          "duration": "30 min",
          "intensity": "Controlled, leave two reps in reserve"
        }
      ]
    },
    {
      "day": "Tuesday",
      "date": "2026-11-03",
      "summary": "6 mi · about 62 min",
      "sessions": [
        {
          "time": "6:00 a.m.",
          "title": "Easy run + strides",
          "detail": "6 mi at 10:15 – 10:45, then 6 x 20s strides on the flat with full recovery",
          "duration": "62 min",
          "intensity": "Easy · zone 2"
        }
      ]
    },
    {
      "day": "Wednesday",
      "date": "2026-11-04",
      "summary": "9 mi · about 80 min",
      "sessions": [
        {
          "time": "6:00 a.m.",
          "title": "Threshold session",
          "tag": "Key",
          "detail": "2 mi warm-up, 2 x 2 mi at 8:10 with 3 min jog between, 3 mi cool-down. Run the second rep no faster than the first.",
          "duration": "80 min",
          "intensity": "Threshold · zone 4"
        }
      ]
    },
    {
      "day": "Thursday",
      "date": "2026-11-05",
      "summary": "6 mi · about 63 min",
      "sessions": [
        {
          "time": "6:00 a.m.",
          "title": "Easy run",
          "detail": "6 mi, all of it easy. Slower than Tuesday if yesterday is still in the legs.",
          "duration": "63 min",
          "intensity": "Easy · zone 2"
        },
        {
          "time": "Evening",
          "title": "Mobility",
          "detail": "Hips and calves, 15 minutes. Optional but you will notice it on Saturday.",
          "duration": "15 min",
          "intensity": "Easy"
        }
      ]
    },
    {
      "day": "Friday",
      "date": "2026-11-06",
      "summary": "3 mi · about 32 min",
      "sessions": [
        {
          "time": "Any time",
          "title": "Shake-out",
          "detail": "3 mi very easy. If you feel flat, walk half of it. Do not skip it entirely — the legs go stiff.",
          "duration": "32 min",
          "intensity": "Easy · zone 2"
        }
      ]
    },
    {
      "day": "Saturday",
      "date": "2026-11-07",
      "summary": "13 mi · about 2h 05m",
      "sessions": [
        {
          "time": "7:30 a.m.",
          "title": "Long run with race pace",
          "tag": "Key",
          "detail": "9 mi easy, then 4 mi at 8:35 to finish. Gels at 45 and 75 minutes. Race kit and race shoes. Start the last 4 slower than you want to.",
          "duration": "2h 05m",
          "intensity": "Easy into half pace"
        }
      ]
    },
    {
      "day": "Sunday",
      "date": "2026-11-08",
      "rest_label": "Rest day",
      "rest_note": "Walk, eat, sleep. No running, and no making up Friday's miles.",
      "summary": "Complete rest"
    }
  ],
  "reminders": [
    "Race kit and race shoes on Saturday, not your training trainers",
    "Two gels for Saturday — the ones you will use on race day",
    "Log Wednesday's splits before you forget them",
    "Next week is a down week: 28 miles, no reps, by design"
  ],
  "log": {
    "heading": "How it went",
    "prompt": "Sleep, soreness, and how Saturday's last four miles felt.",
    "lines": 4
  },
  "footer": "Tick the box when it is done. Move a session rather than skip it, and tell me when you do."
}

Render it

With an API keyshell
curl -sS https://api.galleyrender.com/v1/render \
  -H "Authorization: Bearer $GALLEY_API_KEY" \
  -H 'content-type: application/json' \
  -d '{
  "template": "weekly-schedule@1",
  "format": "pdf",
  "data": "… the example payload above …"
}'
With no API key, over MCPshell
# No API key. The first call mints a trial of 10 PDF pages or 10 images.
curl -sS https://mcp.galleyrender.com/mcp \
  -H 'content-type: application/json' \
  -H 'accept: application/json, text/event-stream' \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "render",
      "arguments": {
        "template": "weekly-schedule",
        "format": "pdf",
        "data": { … see the example payload above … }
      }
    }
  }'

Pin the version — weekly-schedule@1 — in anything you ship. Publishing a new version never changes an old one. Render endpoint reference →

Try a free tool

Renders the example payload on the production service. No account, no key.

JSON Schema

schema.json (11 top-level properties)
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Weekly training schedule",
  "type": "object",
  "required": [
    "client",
    "week",
    "days"
  ],
  "additionalProperties": true,
  "properties": {
    "accent": {
      "type": "string",
      "description": "The one hot accent: the key-session title, the block name and the reminder numerals. A hex colour or a CSS colour keyword. It is interpolated into the stylesheet, so nothing else is accepted.",
      "examples": [
        "#d62828"
      ],
      "default": "#d62828",
      "pattern": "^(#[0-9a-fA-F]{3,8}|[a-zA-Z]{3,20})$"
    },
    "title": {
      "type": "string",
      "default": "This week",
      "examples": [
        "This week"
      ]
    },
    "client": {
      "type": "object",
      "required": [
        "name"
      ],
      "properties": {
        "name": {
          "type": "string",
          "examples": [
            "Nadia Ferreira-Blake"
          ]
        }
      }
    },
    "coach": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "examples": [
            "Owen Castellanos"
          ]
        },
        "business": {
          "type": "string",
          "examples": [
            "Northbank Endurance"
          ]
        },
        "email": {
          "type": "string",
          "format": "email",
          "examples": [
            "owen@northbankendurance.test"
          ]
        },
        "logo_url": {
          "type": "string",
          "format": "uri",
          "examples": [
            "https://example.com/northbank.png"
          ]
        }
      }
    },
    "week": {
      "type": "object",
      "required": [
        "starting"
      ],
      "properties": {
        "starting": {
          "type": "string",
          "format": "date",
          "examples": [
            "2026-11-02"
          ]
        },
        "ending": {
          "type": "string",
          "format": "date",
          "examples": [
            "2026-11-08"
          ]
        },
        "number": {
          "type": "integer",
          "minimum": 1,
          "examples": [
            7
          ]
        },
        "of": {
          "type": "integer",
          "minimum": 1,
          "examples": [
            12
          ]
        },
        "phase": {
          "type": "string",
          "examples": [
            "Build"
          ]
        },
        "focus": {
          "type": "string",
          "description": "One sentence in the bar under the header. This is the thing they will actually read.",
          "examples": [
            "The biggest week of the block. Saturday's long run has four miles of race pace at the end of it, and that is the session that matters."
          ]
        }
      }
    },
    "targets": {
      "type": "array",
      "description": "The figures knocked out of the black bar beside the focus. Four is the most that fits comfortably.",
      "items": {
        "type": "object",
        "required": [
          "label",
          "value"
        ],
        "properties": {
          "label": {
            "type": "string",
            "examples": [
              "Volume"
            ]
          },
          "value": {
            "type": "string",
            "examples": [
              "37 mi"
            ]
          },
          "note": {
            "type": "string",
            "examples": [
              "Up 3 from last week"
            ]
          }
        }
      }
    },
    "days": {
      "type": "array",
      "minItems": 1,
      "maxItems": 7,
      "description": "One block per day. A day with no `sessions` is drawn as a rest day.",
      "items": {
        "type": "object",
        "required": [
          "day"
        ],
        "properties": {
          "day": {
            "type": "string",
            "examples": [
              "Wednesday"
            ]
          },
          "date": {
            "type": "string",
            "format": "date",
            "examples": [
              "2026-11-04"
            ]
          },
          "summary": {
            "type": "string",
            "description": "Right-aligned in the day header, e.g. the day's total.",
            "examples": [
              "9 mi · about 80 min"
            ]
          },
          "rest_label": {
            "type": "string",
            "default": "Rest day",
            "examples": [
              "Rest day"
            ]
          },
          "rest_note": {
            "type": "string",
            "examples": [
              "Walk, stretch, eat. No running."
            ]
          },
          "sessions": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "title"
              ],
              "properties": {
                "time": {
                  "type": "string",
                  "examples": [
                    "6:00 a.m."
                  ]
                },
                "title": {
                  "type": "string",
                  "examples": [
                    "Threshold session"
                  ]
                },
                "tag": {
                  "type": "string",
                  "description": "Pill after the title.",
                  "examples": [
                    "Key"
                  ]
                },
                "detail": {
                  "type": "string",
                  "examples": [
                    "2 mi w/u, 2 x 2 mi at 8:10 w/ 3 min jog, 3 mi c/d"
                  ]
                },
                "duration": {
                  "type": "string",
                  "examples": [
                    "80 min"
                  ]
                },
                "intensity": {
                  "type": "string",
                  "examples": [
                    "Threshold · zone 4"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "reminders_heading": {
      "type": "string",
      "default": "Reminders",
      "examples": [
        "Reminders"
      ]
    },
    "reminders": {
      "type": "array",
      "items": {
        "type": "string",
        "examples": [
          "Race kit and race shoes for Saturday, not the trainers"
        ]
      },
      "examples": [
        [
          "Race kit for Saturday"
        ]
      ]
    },
    "log": {
      "type": "object",
      "description": "Ruled lines for the athlete to write on, for the people who print this and stick it on the fridge.",
      "properties": {
        "heading": {
          "type": "string",
          "default": "How it went",
          "examples": [
            "How it went"
          ]
        },
        "prompt": {
          "type": "string",
          "examples": [
            "Sleep, soreness, anything that felt off. Two lines is plenty."
          ]
        },
        "lines": {
          "type": "integer",
          "minimum": 1,
          "maximum": 20,
          "default": 5,
          "examples": [
            6
          ]
        }
      }
    },
    "footer": {
      "type": "string",
      "description": "Replaces the default tick-the-box line.",
      "examples": [
        "Tick the box when it is done."
      ]
    }
  }
}