# Stat card template

> One big number with its label, change, and period, for reports and year-in-review posts. Render it on-brand from an AI agent or the REST API.

Canonical URL: https://vectorfast.ai/render/templates/stat-card
Markdown URL: https://vectorfast.ai/render/templates/stat-card.md
Last modified: 2026-10-30

VectorFast Render is in early access: billing is not connected yet, and API keys are issued to waitlist members as access opens.

## Summary
- Template id: `stat-card` (pin the major version as `stat-card@1`; current version 1.0.0)
- Sizes: 1080×1080, 1200×630 (default 1080×1080)
- Formats: PNG, JPEG, WebP
- Use it for: Investor and team updates; Year-in-review and usage recap cards; Dashboard snapshots for social posts

## Previews
- English: ![Stat card template rendered in English at 1080×1080 with the built-in VectorFast brand kit.](https://vectorfast.ai/i/stat-card.png?brand=default&delta=%2B4%20pts&footnote=Edge%20and%20R2%20hits%20over%20all%20signed-URL%20requests.&h=1080&label=of%20renders%20served%20from%20cache&period=October%202026&value=98%25&w=1080&sig=sXOB90UZ55w67q5X-mLKUL-PMcCd48y7dUQYJP3Hous)
- Chinese: ![Stat card template rendered in Chinese at 1080×1080 with the built-in VectorFast brand kit.](https://vectorfast.ai/i/stat-card.png?brand=default&delta=%2B38%25&footnote=%E7%BB%9F%E8%AE%A1%20API%20%E4%B8%8E%20MCP%20%E6%B8%B2%E6%9F%93%EF%BC%8C%E4%B8%8D%E5%90%AB%E7%BC%93%E5%AD%98%E5%91%BD%E4%B8%AD%E3%80%82&h=1080&label=%E6%9C%AC%E5%AD%A3%E5%BA%A6%E6%B8%B2%E6%9F%93%E7%9A%84%E5%93%81%E7%89%8C%E5%9B%BE&period=2026%20%E5%B9%B4%E7%AC%AC%E4%B8%89%E5%AD%A3%E5%BA%A6&value=120%20%E4%B8%87&w=1080&sig=5jZUZlOkIe6IuThbwqIzFsJLEs33gZuQa_DV0T232tU)

## Parameters
All string params are trimmed. Limits come from the schema `POST /v1/renders` validates.

| Param | Type | Required | Limit | Notes |
| --- | --- | --- | --- | --- |
| `value` | string | yes | ≤ 12 chars | Pre-formatted number such as "1.2M" or "98%"; the template does not format numbers. |
| `label` | string | yes | ≤ 80 chars | What the number counts. |
| `delta` | string | no | ≤ 16 chars | Change such as "+38%". |
| `period` | string | no | ≤ 30 chars | Time window such as "Q3 2026". |
| `footnote` | string | no | ≤ 120 chars | Source or definition in small print. |

## Ask an agent
Prompt:

> Turn this into a square stat card for our Q3 investor update: 1.2M images rendered in Q3, up 38% on Q2. Add a footnote that it counts API and MCP renders.

The MCP `render` tool call it should become:

```json
{
  "name": "render",
  "arguments": {
    "template": "stat-card",
    "params": {
      "value": "1.2M",
      "label": "images rendered",
      "delta": "+38%",
      "period": "Q3 2026",
      "footnote": "Counts API and MCP renders; cache hits excluded."
    },
    "width": 1080,
    "height": 1080
  }
}
```

## REST
```bash
curl https://vectorfast.ai/v1/renders \
  -H "Authorization: Bearer $VECTORFAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "template": "stat-card@1",
  "format": "png",
  "width": 1080,
  "height": 1080,
  "params": {
    "value": "1.2M",
    "label": "images rendered",
    "delta": "+38%",
    "period": "Q3 2026",
    "footnote": "Counts API and MCP renders; cache hits excluded."
  }
}'
```

## Signed URL (server-side Node.js)
Per-key signing secrets are not issued yet in early access; until then, reuse the signed `url` that `POST /v1/renders` returns. The algorithm below is what the server verifies. Keep the secret on your server.

```js
import { createHmac } from 'node:crypto'

// Server-side only. Never ship the signing secret to a browser, a mobile app or a repo.
const SIGNING_SECRET = process.env.VECTORFAST_SIGNING_SECRET

function encode(value) {
  return encodeURIComponent(value).replace(/[!'()*]/g, c => '%' + c.charCodeAt(0).toString(16).toUpperCase())
}

export function signRenderUrl({ template, format = 'png', params, brand, width, height, keyId }, secret = SIGNING_SECRET) {
  const query = {}
  for (const [key, value] of Object.entries(params)) {
    if (value === undefined || value === null)
      continue
    query[key] = typeof value === 'string' ? value : Array.isArray(value) ? JSON.stringify(value) : String(value)
  }
  if (brand) query.brand = brand
  if (keyId) query.k = keyId
  if (width) query.w = String(width)
  if (height) query.h = String(height)

  const canonical = Object.entries(query)
    .map(([key, value]) => [encode(key), encode(value)])
    .sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0))
    .map(([key, value]) => key + '=' + value)
    .join('&')
  const path = '/i/' + template + '.' + format
  const sig = createHmac('sha256', secret).update(path + '?' + canonical).digest('base64url')
  return 'https://vectorfast.ai' + path + '?' + (canonical ? canonical + '&' : '') + 'sig=' + sig
}

const url = signRenderUrl({
  template: 'stat-card',
  format: 'png',
  width: 1080,
  height: 1080,
  params: {
    "value": "98%",
    "label": "of renders served from cache",
    "delta": "+4 pts",
    "period": "October 2026",
    "footnote": "Edge and R2 hits over all signed-URL requests."
  },
})
```

## FAQ
### Which sizes does the stat-card template support?
1080×1080, 1200×630. The default is 1080×1080; pass width and height to pick another supported size.

### Which parameters are required?
value and label. Every other parameter is optional and has a rendering default.

### Does rendering the same parameters twice cost twice?
No. The same template version, parameters, brand kit version, format, and size produce the same cache key, so a repeat request is served from cache instead of rendering again. Billing is not connected yet in early access.

## Related
- All templates: https://vectorfast.ai/render/templates
- Template reference: https://vectorfast.ai/render/docs/templates
- Connect Claude: https://vectorfast.ai/render/agents/claude
