Release notes
Tell the client what shipped
A release note is a line I write when a version goes out. It is not the work log, and it is not a read of the Git repository. I type it, or a script posts it. The client sees the public ones. I keep the internal ones for myself.
Where a note shows
- Public, on a care site or an app: the public status page, under What shipped. I show the latest public notes, up to 12.
- Public, on a care site: the client digest for that report period, again under What shipped. The digest email lists up to five of those titles. An app does not send a care digest.
- Internal: the dashboard list only. The status page and the digest leave it out.
A proof pack is not a care site and not an app. The release routes return 404 for one.
Fields
titleis required. 140 characters at most.versionis optional. 40 characters at most. I leave it blank when the note is not a numbered release.bodyis Markdown, optional, 8000 characters at most. I escape raw HTML when I render the page. A script tag stays text.releasedAtis an ISO time orYYYY-MM-DD. Leave it out, or leave the dashboard field blank, and I use the current time.visibilityispublicorinternal. The dashboard and the API both default to public when you do not choose.sourceismanual,api, orgit. The dashboard stores manual. The API stores api when you omit it.commitShais an optional hex string, 7 to 64 characters.urlis an optional http or https address. I store both for a later git view. I do not draw them on the status page or the digest.
A site or an app holds 80 notes. The 81st comes back as 409 with error set to release_limit. A bad field is 422. An id from another account, a missing id, or a proof pack is 404.
Add one in the dashboard
- Open the care site, or the app. The section is Release notes.
- Version, if you have one. Title. Body, if you want more than the title. I accept Markdown.
- Released can stay empty. Visibility is Public on the status page, or Internal only.
- Add release. Edit and Delete sit on the row after that.
This is the note I use when I want a client to see a checkout change. Paste the lines into the form.
Version: 1.4.0
Title: Faster checkout
Body: Checkout keeps the cart when a card is declined.
Visibility: Public on the status page
The same form is on an app. Public notes there show on that app's status page, not on a care digest.
Add one with curl
Create the key under Brand settings, then API keys. Send it as a Bearer token. This posts a public note on a care site or an app. Replace SITE_ID.
curl -sS -X POST https://retainerproof.com/api/v1/sites/SITE_ID/releases \
-H "Authorization: Bearer rp_live_…" \
-H "Content-Type: application/json" \
-d '{"title":"Faster checkout","version":"1.4.0","body":"Checkout keeps the cart when a card is declined.","visibility":"public"}'
The response is 201 and release.id. GET lists the notes, including internal ones. PATCH and DELETE use /api/v1/sites/SITE_ID/releases/RELEASE_ID. The same paths work when SITE_ID is an app id. The full field list is on the API reference.
GitHub Actions on a tag
I do not read the repository. This workflow only runs when a tag is pushed, and the step only calls the API. Store the key as a repository secret named RETAINERPROOF_KEY. Replace SITE_ID.
name: Release note
on:
push:
tags:
- "v*"
jobs:
note:
runs-on: ubuntu-latest
steps:
- name: Post the release
env:
RETAINERPROOF_KEY: ${{ secrets.RETAINERPROOF_KEY }}
run: |
curl -sS -f -X POST https://retainerproof.com/api/v1/sites/SITE_ID/releases \
-H "Authorization: Bearer $RETAINERPROOF_KEY" \
-H "Content-Type: application/json" \
-d "{\"title\":\"${GITHUB_REF_NAME}\",\"version\":\"${GITHUB_REF_NAME}\",\"visibility\":\"public\",\"source\":\"api\",\"body\":\"Shipped ${GITHUB_REF_NAME}.\"}"
GitLab CI on a tag
Same idea. The job runs when CI_COMMIT_TAG is set. Add RETAINERPROOF_KEY as a masked CI/CD variable. I still do not read the GitLab project. The job posts one note.
release-note:
rules:
- if: $CI_COMMIT_TAG
script:
- |
curl -sS -f -X POST https://retainerproof.com/api/v1/sites/SITE_ID/releases \
-H "Authorization: Bearer $RETAINERPROOF_KEY" \
-H "Content-Type: application/json" \
-d "{\"title\":\"${CI_COMMIT_TAG}\",\"version\":\"${CI_COMMIT_TAG}\",\"visibility\":\"public\",\"source\":\"api\",\"body\":\"Shipped ${CI_COMMIT_TAG}.\"}"
n8n or Zapier
I do not ship an n8n node or a Zapier app. Both tools can send the same HTTP request I use from curl.
- Add an HTTP Request step. Method POST. URL
https://retainerproof.com/api/v1/sites/SITE_ID/releases. - Header
Authorizationwith the valueBearer rp_live_…. HeaderContent-Typewithapplication/json. - Body, JSON:
{"title":"Faster checkout","version":"1.4.0","body":"Checkout keeps the cart when a card is declined.","visibility":"public"}
In n8n that is the HTTP Request node, with the key in a header credential so the key is not sitting in the workflow JSON. In Zapier it is an HTTP request, sometimes labeled Webhooks by Zapier. Stop on 409 and on 429. A 429 includes Retry-After in seconds. The account still needs an active subscription, and the limit is 60 requests a minute per key.
Also see adding a site from a script and the API reference.