Post a message to my Discord channel every time someone buys my Yard project, using a Yard webhook and a small service hosted on Yard.
1. Check yard me --json for .team_permissions.service and webhooks. If either is missing, stop and give me https://yard.sh/pricing. In the Yard project linked to this directory, create notify/_service.js and add {"dir": "notify", "name": "notify", "url": "/notify", "access": "public"} to services in .yard/settings.json.
2. Handle POST /sale. Read the raw body as text and verify the X-Yard-Signature header, which looks like t=<unix seconds>,v1=<hex>. Split it on commas into key=value pairs, require a digits-only t and a v1, and reject a t more than 300 seconds from now. v1 is the hex HMAC-SHA256 of t exactly as received, then ".", then the raw body, keyed with the env.YARD_WEBHOOK_SECRET string as-is (don't hex-decode it). Use Web Crypto and a constant-time compare, and answer 401 if any check fails. On a "sale.completed" event, post project_slug, tier_name, quantity and amount_cents (formatted as money) to env.DISCORD_WEBHOOK_URL. Skip any event that carries a sandbox field: it is a test sale from one of my sandboxes, so post nothing. Answer 200 quickly for every verified event, including webhook.ping.
3. Put test values for both secrets in .yard/dev/secrets.env, run yard dev in the background, and send a sample sale.completed body signed the way Yard signs it: T=$(date +%s); SIG=$(printf '%s.%s' "$T" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | sed 's/^.* //'); curl -H "Content-Type: application/json" -H "X-Yard-Signature: t=$T,v1=$SIG" --data-binary "$BODY" <local URL>/notify/sale. Send the same sample with "sandbox": "beta" added and confirm it gets 200 without posting to Discord. Confirm a bad signature and a t from 10 minutes ago both get 401. Then run yard service check and yard push.
4. Give me the hosted URL https://<team username>.yard.sh/<slug>/notify/sale and have me create the webhook in the Yard dashboard (Configure, then Webhooks), copy its signing secret (Yard creates it with the URL) and paste it to you along with my Discord webhook URL. Set both with yard service secrets set.
Ask me before you run yard releases publish. Note that Yard can only reach the service once the project is out of draft.