ThreeSixtyFiveAPI Reference
GET/api/generate

Wallpaper Generator API

A single HTTP endpoint that generates a phone wallpaper image (PNG or SVG) showing your year progress, life calendar, or goal countdown — updated to the current day in any timezone.

Quick Start

Make a GET request with query parameters. The response is a raw image — you can use it directly in <img> tags, iOS Shortcuts, or Android MacroDroid.

bash
curl "https://365tsf.vercel.app/api/generate?country=us&type=year&bg=000000&accent=FFFFFF&width=1206&height=2622" \
  --output wallpaper.png

Format

PNG (default) or SVG

Rate limit

20 req / 60s per IP

Cache

24h Cache-Control

Parameters

All parameters are passed as query strings. Only country is strictly required; everything else falls back to a sensible default.

Core
ParameterTypeDefaultDescription
countryrequired
stringusISO 3166-1 alpha-2 country code (lowercase). Used to derive the timezone so the correct day is highlighted. E.g. us, gb, in, jp.
type
enumyearWallpaper style. One of year, life, or goal.
bg
hex000000Background color as a 6-digit hex string without the #. E.g. 0a0a0a.
accent
hexFFFFFFAccent / dot color as a 6-digit hex string. E.g. FFD700.
width
integer1170Canvas width in pixels. Min 300, max 8000.
height
integer2532Canvas height in pixels. Min 300, max 8000.
clockHeight
float0.18Fraction of canvas height reserved for the lock screen clock (0–0.5). iPhone 16 Pro uses 0.18; adjust per device.
format
enumpngOutput format. png (default) or svg.
Life Calendar (type=life)
ParameterTypeDefaultDescription
dob
YYYY-MM-DDDate of birth. If omitted, defaults to 25 years before today.
lifespan
integer80Expected lifespan in years (1–120). Determines total grid rows.
Goal Countdown (type=goal)
ParameterTypeDefaultDescription
goalrequired
YYYY-MM-DDTarget date to count down to.
goalStart
YYYY-MM-DDWhen you started tracking. Used to calculate arc progress. Must be ≤ goal. Defaults to 30 days before the target.
goalName
stringGoalLabel shown on the wallpaper (max 100 chars). URL-encode special characters.

Year Progress

365 or 366 dots arranged in a 15-column grid. Completed days are filled, today's dot is slightly larger, and remaining days are dimmed. A stats line below the grid shows days left and percentage complete.

countrybgaccentwidthheightclockHeight
bash
curl "https://365tsf.vercel.app/api/generate?country=us&type=year&bg=000000&accent=FFFFFF&width=1206&height=2622"

Life Calendar

52 columns × lifespan rows — one dot per week of your life. Weeks lived are filled, the current week is highlighted, and future weeks are faint. Stats show weeks remaining and percentage lived.

countrybgaccentwidthheightclockHeightdoblifespan
bash
curl "https://365tsf.vercel.app/api/generate?country=us&type=life&bg=000000&accent=FFFFFF&width=1206&height=2622&dob=1995-06-15&lifespan=80"

Goal Countdown

A circular arc that shrinks as days pass toward the target date. The center shows days remaining. The arc represents the proportion of time left from start to goal.

countrybgaccentwidthheightclockHeightgoalgoalStartgoalName
bash
curl "https://365tsf.vercel.app/api/generate?country=us&type=goal&bg=000000&accent=FFFFFF&width=1206&height=2622&goal=2025-12-31&goalName=Launch"

Examples

Year progress — iPhone 17 Pro, gold accent

bash
curl "https://365tsf.vercel.app/api/generate?country=us&type=year&bg=0a0a0a&accent=FFD700&width=1206&height=2622&clockHeight=0.18"

Life calendar — born 1995, 85 year lifespan

bash
curl "https://365tsf.vercel.app/api/generate?country=gb&type=life&bg=000000&accent=00D4FF&width=1206&height=2622&dob=1995-06-15&lifespan=85"

Goal countdown — product launch

bash
curl "https://365tsf.vercel.app/api/generate?country=us&type=goal&bg=0a0a0a&accent=FF3B30&width=1206&height=2622&goal=2025-12-31&goalStart=2025-01-01&goalName=Product%20Launch"

Fetch in JavaScript

javascript
const params = new URLSearchParams({
  country: "us",
  type: "year",
  bg: "000000",
  accent: "FFFFFF",
  width: "1206",
  height: "2622",
});

const res = await fetch(`/api/generate?${params}`);
const blob = await res.blob();
const url = URL.createObjectURL(blob);

document.querySelector("img").src = url;

iOS Shortcut — "Get Contents of URL" action

text
URL:
https://365tsf.vercel.app/api/generate?country=us&type=year&bg=000000&accent=FFFFFF&width=1206&height=2622&clockHeight=0.18

Then: Set Wallpaper Photo → Lock Screen
      ↳ Disable "Crop to Subject"
      ↳ Disable "Show Preview"

Errors & Rate Limits

The endpoint is rate limited to 20 requests per 60 seconds per IP address. Every response includes rate limit headers so you can track usage.

200

Success — image data returned.

400

Validation error — a parameter is missing, out of range, or malformatted. Response body is JSON with an issues array.

429

Too Many Requests — rate limit exceeded. Check Retry-After header.

500

Internal Server Error — image generation failed.

400 Validation error body

json
{
  "error": "Validation Error",
  "issues": [
    {
      "code": "invalid_type",
      "path": ["width"],
      "message": "Expected number, received nan"
    }
  ]
}

429 Rate limit body

json
{
  "error": "Too Many Requests",
  "message": "Rate limit exceeded. Try again in 42s."
}

Response Headers

HeaderDescription
Content-Typeimage/png or image/svg+xml depending on format param
Cache-Controlpublic, max-age=86400 — safe to cache for 24 hours
X-RateLimit-LimitMaximum requests allowed per window (20)
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetSeconds until the window resets
Retry-AfterSeconds to wait before retrying (only on 429)

Built by avalynndev