CheckCourt
App platform

Notifications

Notify members through CheckCourt without ever learning their contact data

Your app can send a member a short message. CheckCourt delivers it: in the member's CheckCourt inbox (the bell at the top of the navigation, next to the club's name) and, if they allow it, by email. Your app never sees an email address or phone number, and it never learns whether the member muted it.

curl -X POST "https://app.checkcourt.de/api/v1/app/notifications" \
  -H "Authorization: Bearer cca_…" \
  -H "Content-Type: application/json" \
  -d '{
    "recipient": "psn_4hQ2v0bD1xZk8yWm3nT7aLc9eRf",
    "title": "Your ball machine is ready",
    "body": "Court 3 from 5:30 pm. The balls are in the basket next to the net.",
    "url": "/booking?date=2026-05-01",
    "idempotency_key": "reservation-8812-ready"
  }'
{ "id": "ntf_k3x9…", "accepted": true }

With the SDK:

import { sendNotification } from "@checkcourt/sdk";

// claims: a verified extension context token (viewer.user_id is a psn_… pseudonym
// unless the installation holds members:read)
const { id } = await sendNotification(client, {
  recipient: claims.viewer.user_id!,
  title: "Your ball machine is ready",
  body: "Court 3 from 5:30 pm.",
  url: "/booking?date=2026-05-01",
  idempotencyKey: "reservation-8812-ready",
});

Scope

Add notifications:send to tenantScopes (club app) or userScopes (member app):

{
  "tenantScopes": ["bookings:read", "notifications:send"],
  "userScopes": ["notifications:send"]
}

notifications:send is an app-only scope. No club role holds it, not even Administrator, so the person installing your app does not need it. For a member app the member's consent is enough. Clubs see it as „Benachrichtigungen schicken“ (send notifications), members as a promise that the app can reach them through CheckCourt without learning their contact data. Adding it later is a new scope, so clubs and members consent again before the new version runs.

Who you can notify

recipient takes only an id your app legitimately received. Everything else, including ids of other clubs, members waiting for approval, removed members and ids your token may not use, returns the same 404. You cannot probe who exists.

TokenAccepted recipient
Club app (cca_)the CheckCourt user id, only if the installation holds members:read
the pseudonym psn_… from an extension context, bound to this installation
the pairwise id usr_… from GET /api/v1/me, for members who connected your app
Member app (ccu_)only the member who connected it: their pairwise usr_… id or their user id

Pseudonyms are per installation: a psn_… from one club's installation does not work for another.

Message

FieldRules
recipientsee above
title1 to 80 characters, one line of plain text
body1 to 500 characters, plain text, line breaks are kept. HTML is shown as text
urloptional. A path inside CheckCourt such as /booking?date=2026-05-01 (not /api/…), or an https link on an origin you registered: one of your redirect URIs or the listing's connect URL
categoryoptional label for your own kind of message, ^[a-z0-9][a-z0-9_.-]{0,39}$
idempotency_keyoptional, up to 100 visible ASCII characters

Write in German, in the tone of the club: the title says what happened, the body what the member can do. Leave out greetings and signatures; CheckCourt shows your app's name and icon next to every message.

Delivery

  • Inbox: always, unless the member switched off „In CheckCourt“ for your app.
  • Email: unless the member switched off email for your app or for all apps. CheckCourt sends at most 3 emails per member and app per day; later messages that day only reach the inbox. The email shows your app's name, the title, the body and a button to the link, and tells the member how to mute your app.
  • Sandbox clubs: emails only go to members of your developer organization. Invented sandbox members get the inbox entry only.
  • Push: not yet.

The response is the same either way: { "id", "accepted": true }. It does not say whether the member saw the message or got an email.

Limits

LimitValue
Per installation60 per minute, 1,000 per day
Per member and app10 per day

Over a limit you get 429 with Retry-After in seconds. The usual per-token limit of 120 requests per minute applies as well.

Idempotency

Send an idempotency_key when you might retry. Within 24 hours the same key on the same installation returns the first notification's id and sends nothing again, even if the body differs.

Errors

StatusCodeWhen
400VALIDATIONa field breaks the rules above, or an unknown field
401UNAUTHORIZEDmissing or expired token, app uninstalled or disconnected
403FORBIDDENthe token lacks notifications:send, or it is an API key
404NOT_FOUNDno member your app may notify under this id
422BUSINESS_RULEthe club paused notifications for your app
429RATE_LIMITEDa limit was reached, see Retry-After

Control by members and clubs

  • Members mute your app per channel under Einstellungen → Benachrichtigungen von Apps (Settings → Notifications from apps), or switch off emails from all apps.
  • Club admins see on your installation's page how many messages you sent in the last 30 days and can pause your notifications. While paused, every request fails with 422. The pause also covers members who connected your app.
  • After uninstall or disconnect your tokens stop working at once. Messages already delivered stay in the member's inbox with your app's name.

There are no webhooks for notifications: you won't learn whether a message was read.

On this page