Kicksmash
My matches
Developers · assistants · agents

Kicksmash is the open, agent-native way to organise padel: create a match, share one link, and let people or their assistants join, all through an API that anyone may use.

For assistants: add the MCP server

One URL. Reads need nothing; creating and joining works without a key within a daily allowance. Tools: about_kicksmash, get_match, find_matches, get_group, generate_schedule, create_match, join_match, create_api_key.

https://kicksma.sh/mcp
Claude (web or desktop)

Settings → Connectors → Add custom connector → paste the URL.

Claude Code
claude mcp add --transport http kicksmash https://kicksma.sh/mcp
ChatGPT

Settings → Connectors → Advanced → Developer mode → Create → paste the URL, no authentication.

Cursor, Windsurf, others
{ "mcpServers": { "kicksmash": { "url": "https://kicksma.sh/mcp" } } }

Discovery for machines: /llms.txt, /llms-full.txt, /.well-known/mcp.json, /api/openapi.json. What we ask of assistants is on /agents.

REST in three calls

Read a match (no key):

curl https://kicksma.sh/api/v1/matches/PLAY

Create a match for someone (a key is optional; without one, 12 writes a day per address):

curl -X POST https://kicksma.sh/api/v1/matches \
  -H "Content-Type: application/json" \
  -d '{"startsAt":"2026-09-11T19:00","tz":"Asia/Singapore","venue":"Club Nine",
       "organizer":{"name":"Ana"},"levelMin":3,"levelMax":4.5}'

Join by first name:

curl -X POST https://kicksma.sh/api/v1/matches/AB12/join \
  -H "Content-Type: application/json" -d '{"name":"Bo","level":3.5}'

Responses carry a next sentence saying what to do with the links. Errors carry a hint. The full contract is the OpenAPI 3.1 document.

A key, if you want more room

Instant, free, no approval. Raises writes to 300 a day and unlocks webhooks. Assistants may request their own with the create_api_key tool or POST /api/v1/keys.

Webhooks

Signed callbacks on match.created, match.updated, match.joined, match.left, match.full, match.cancelled, match.result. Filter by venue, group or match codes. Retried with backoff for a day.

curl -X POST https://kicksma.sh/api/v1/webhooks -H "Authorization: Bearer ks_live_…" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/hooks/kicksmash","events":["match.created","match.full"],"filter":{"venueSlug":"club-nine"}}'

Verify X-Kicksmash-Signature: t=<unix>,v1=<hex> as HMAC-SHA256 of "<unix>.<raw body>" with the secret returned at creation.

Calendars, feeds, embeds

Telegram, where the players are

The bot (@kicksmash_bot) keeps one live card per match in a group chat and stays quiet otherwise. /new asks for a day, a time and a place with buttons, or takes one line: /new tomorrow 19:00 Rawai (a cost such as 400฿ and a level range such as 3-4 are optional words). People tap I'm in; after the match, 🏁 on the card records who won and the organizer confirms. Typing @kicksmash_bot in any chat shares a live card without adding the bot; the Mini App at t.me/kicksmash_bot/KickSmash opens the site signed in. Every change made there goes through the same API and webhooks as the web, so your integration sees it all.

Portable levels: the passport

A player who switches their public page on gets a signed level document at /u/{slug}/passport.json (people get the readable version at /u/{slug}/passport): name, level, band, whether an organizer confirmed it, matches played and won, issued and expiry dates. Ed25519 over canonical JSON (keys sorted, no whitespace, every field except alg and sig). The public key is at /.well-known/kicksmash-passport.json. Profiles are opt-in and off by default; there is no list of them, and you should never guess a slug.

import { verifyPassport } from "@erikv69/levels";

const doc = await fetch("https://kicksma.sh/u/ana-x7k2m/passport.json").then((r) => r.json());
const { keys } = await fetch("https://kicksma.sh/.well-known/kicksmash-passport.json").then((r) => r.json());
const key = keys.find((k) => k.kid === doc.kid);
const ok = key && (await verifyPassport(doc, key.hex)) && new Date(doc.expiresAt) > new Date();

The same package maps other apps' scales onto 0–7 (fromScale); the table is on /levels. Players can also download everything Kicksmash holds about them as one JSON file from My matches.

Licence and limits

Code: Apache-2.0. Public match, board, group and schedule data: CC BY 4.0, attribute "Kicksmash, kicksma.sh". Personal data (emails, phones, tokens, manage links) is never in the public data.

Limits without a key: 600 reads an hour, 12 writes a day per address, 300 MCP calls an hour. With a key: five times the reads, 300 writes a day, 10 webhooks. Need more, or building something? Say so in GitHub Discussions or on Discord.

Building your own padel tool with an assistant? npx skills add evhg/padel-matchup installs a skill that teaches it this API. The repository also carries an AGENTS.md.