Workout Link Spec.
Copy the spec below and paste it into any AI agent: ChatGPT, Claude, Gemini, or your own. Describe the workout you want and the agent will produce a paceo:// link. Tap it on your iPhone and the workout opens in Paceo ready to save or schedule.
Links open the Paceo iOS app. The app is required; links won't work in a browser.
PACEO WORKOUT LINK SPEC v1
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Generate deep links that open workout previews directly in the Paceo iOS app.
The user taps the link → Paceo shows the workout → they save or schedule it.
─── URL FORMAT ─────────────────────────────────────────────────────────────────
paceo://workout?d={encoded_payload}
─── ENCODING ───────────────────────────────────────────────────────────────────
1. Build a JSON payload (schema below)
2. Compress with zlib (deflate, RFC 1950)
3. Encode as URL-safe base64: replace + → - and / → _ and strip trailing =
Python:
import json, zlib, base64
def make_link(name: str, plan: dict) -> str:
payload = json.dumps({"v": 1, "n": name, "p": plan}, separators=(",", ":"))
compressed = zlib.compress(payload.encode())
b64 = base64.b64encode(compressed).decode().replace("+","-").replace("/","_").rstrip("=")
return f"paceo://workout?d={b64}"
Node.js (requires pako: npm install pako):
import pako from "pako"
function makeLink(name, plan) {
const bytes = pako.deflate(JSON.stringify({ v: 1, n: name, p: plan }))
let bin = ""; bytes.forEach(b => bin += String.fromCharCode(b))
return "paceo://workout?d=" + btoa(bin).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")
}
─── PAYLOAD SCHEMA ─────────────────────────────────────────────────────────────
{
"v": 1, // version, always 1
"n": string, // workout name (required, non-empty)
"p": WorkoutPlan
}
─── WorkoutPlan ────────────────────────────────────────────────────────────────
Three types: "goal", "pacer", "custom"
TYPE 1: goal-based workout
{ "type": "goal",
"workout": {
"activity": ActivityType,
"location": LocationType,
"swimmingLocation"?: SwimmingLocationType, // only when activity is swimming
"goal": WorkoutGoal
}
}
TYPE 2: pacer (finish a distance in a target time)
{ "type": "pacer",
"workout": {
"activity": ActivityType,
"location": LocationType,
"distance": { "value": number, "unit": DistanceUnit },
"time": { "value": number, "unit": TimeUnit }
}
}
TYPE 3: custom interval workout
{ "type": "custom",
"workout": {
"activity": ActivityType,
"location": LocationType,
"displayName"?: string,
"warmup"?: WorkoutStep,
"blocks": IntervalBlock[],
"cooldown"?: WorkoutStep
}
}
─── WorkoutGoal ────────────────────────────────────────────────────────────────
{ "type": "open" }
{ "type": "time", "value": number, "unit": TimeUnit }
{ "type": "distance", "value": number, "unit": DistanceUnit }
{ "type": "energy", "value": number, "unit": EnergyUnit }
─── WorkoutStep ────────────────────────────────────────────────────────────────
{ "goal": WorkoutGoal, "alert"?: WorkoutAlert }
─── WorkoutAlert (optional coaching zone) ──────────────────────────────────────
{ "type": "heartRate" | "pace" | "speed" | "power" | "cadence",
"target": { "min": number, "max": number, "unit": string },
"metric": "current" | "average" | "maximum" }
Common units by alert type:
heartRate → "bpm"
pace → "min/km" or "min/mi"
speed → "km/h" or "mph"
power → "watts"
cadence → "rpm" (cycling) or "spm" (running)
─── IntervalBlock / IntervalStep ───────────────────────────────────────────────
IntervalBlock : { "steps": IntervalStep[], "iterations": number }
IntervalStep : { "purpose": "work" | "recovery", "step": WorkoutStep }
─── ENUMS ──────────────────────────────────────────────────────────────────────
ActivityType:
running, cycling, swimming, walking,
golf, tennis, basketball, soccer, hockey, baseball, softball, volleyball,
badminton, tableTennis, squash, racquetball, lacrosse, cricket, rugby,
football, americanFootball, australianFootball,
gymnastics, boxing, kickboxing, martialArts,
pilates, yoga, dance, danceInspiredTraining, barre,
coreTraining, flexibility, strengthTraining, traditionalStrengthTraining,
functionalStrengthTraining, crossTraining, mixedCardio, handCycling,
cardioDance, socialDance, cardioCooldown, cooldown, other
LocationType : "indoor" | "outdoor" | "unknown"
SwimmingLocationType : "pool" | "openWater" | "unknown"
TimeUnit : "seconds" | "minutes" | "hours"
DistanceUnit : "meters" | "kilometers" | "yards" | "miles" | "feet"
EnergyUnit : "calories" | "kilocalories" | "joules" | "kilojoules"
─── EXAMPLES ───────────────────────────────────────────────────────────────────
# 10 km outdoor run with distance goal
make_link("10K Run", {
"type": "goal",
"workout": {
"activity": "running",
"location": "outdoor",
"goal": { "type": "distance", "value": 10, "unit": "kilometers" }
}
})
# 5 × 4 min hard / 2 min easy: VO2max running intervals
make_link("VO2max Intervals", {
"type": "custom",
"workout": {
"activity": "running",
"location": "outdoor",
"warmup": { "goal": { "type": "time", "value": 10, "unit": "minutes" } },
"blocks": [{
"iterations": 5,
"steps": [
{ "purpose": "work",
"step": {
"goal": { "type": "time", "value": 4, "unit": "minutes" },
"alert": { "type": "heartRate",
"target": { "min": 155, "max": 175, "unit": "bpm" },
"metric": "current" }
}
},
{ "purpose": "recovery",
"step": { "goal": { "type": "time", "value": 2, "unit": "minutes" } }
}
]
}],
"cooldown": { "goal": { "type": "time", "value": 5, "unit": "minutes" } }
}
})
# 30-min steady cycling pacer at 200W
make_link("Tempo Ride", {
"type": "pacer",
"workout": {
"activity": "cycling",
"location": "indoor",
"distance": { "value": 15, "unit": "kilometers" },
"time": { "value": 30, "unit": "minutes" }
}
})
# 1500m pool swim with open goal
make_link("1500m Swim", {
"type": "goal",
"workout": {
"activity": "swimming",
"location": "indoor",
"swimmingLocation": "pool",
"goal": { "type": "distance", "value": 1500, "unit": "meters" }
}
})
1
Copy the spec
Hit copy spec above and paste it into any AI chat or system prompt.
2
Describe your workout
Ask the agent to generate a link: “5×1km intervals at threshold pace with a 10 min warmup”.
3
Tap the link
Open the
paceo:// link on your iPhone. Review the workout and save or schedule it.