Server patterns
Requires: A secret key holding the scope named on each route, called from your server.
Secret key only. Every route on this page acts with the community's authority: it edits tiers, sends email to the whole community, publishes content, moves money or mints member credentials. Call them from your server with a secret key holding the scope named on each route. A publishable key is refused on all of them, and none of these scopes can be added to one.
These routes are not wrapped by @cobuntu/embed, which is built for the
member-facing site. Call them with fetch:
const res = await fetch(`https://api.cobuntu.com/api/v1/communities/${tag}/broadcasts`, {
method: "POST",
headers: { "X-API-Key": process.env.COBUNTU_SECRET_KEY!, "Content-Type": "application/json" },
body: JSON.stringify({ subject: "October news", htmlContent: "<p>Hello members</p>" }),
});
if (!res.ok) throw new Error((await res.json()).error);Errors are { error, code?, ...details }. Most of these older routes send no
code: branch on the HTTP status. Every write here also counts against the
120 writes per minute per key limit. Full request and response schemas for
each route are in the API reference.
Acting user: where a write needs one (articles, broadcasts, rejections, subscription cancels, event edits), it is recorded as made by the community's founder, because an API key is a community-owned credential rather than a person.
Membership tiers
Endpoint: PATCH /segments/{segmentId}
Scope WRITE_SEGMENTS
Edit an existing tier. Send any subset of name, description, color,
isActive, priceMonthly, priceYearly, priceOneTime (all prices in
cents) and currency. Answers the updated tier.
{ "priceMonthly": 1800, "isActive": true }| Status | Meaning |
|---|---|
400 { error: "No updatable fields supplied", allowed: [...] } | Nothing recognised in the body. |
400 | A price was set before the community connected Stripe. |
404 | No such tier in this community. |
Creating and deleting tiers is not available over the API: both have billing consequences that stay in the dashboard.
Rules acceptance by email
Endpoint: POST /rules/accept
Scope WRITE_MEMBERS
Record that the person with this email accepted the community rules, for example when your own sign-up form shows the rules. You name the email, so this is server side only: the caller vouches for it.
{ "email": "alex@example.com" }400 Valid email is required for a missing or malformed email. For a
signed-in member accepting on your site, use me.onboarding.rules() instead,
which identifies them by their session.
Email broadcasts
Endpoint: POST /broadcasts
Scope WRITE_BROADCASTS
Create and send an email campaign in one call.
| Field | Notes |
|---|---|
subject | Required. |
htmlContent | Required. The email body as HTML. |
previewText | The inbox preview line. |
audience | all (default), approved or pending, when not sending by tier. |
segmentIds | Send to these membership tiers. |
includeApproved, includePending | Narrow a tier send by membership state. |
Answers 201 with the sent campaign. Limits: 5 broadcasts per community per
24 hours, counting broadcasts sent from the dashboard too (429 with
limit, windowHours, recentSends). 400 No recipients found (with the
campaignId it created) means the audience filter matched nobody; 409 means
the campaign could not be sent.
Articles
Endpoints:
POST /articlesPATCH /articles/{articleId}POST /articles/{articleId}/publishPOST /articles/{articleId}/unpublish
Scope WRITE_ARTICLES
For a CMS or editorial pipeline that publishes into the community's journal.
- Create takes
title(required),content(HTML),excerpt,metaTitle,category,bannerUrl,keywords[]andreferences[] ({ label, url? }). The article is created as a draft.201with the article. - Update takes any subset of the same fields, plus
status.400 No editable fields in request bodywhen nothing is recognised. - Publish requires a
bannerUrl(409 Article must have a bannerUrl before it can be published). Settingstatus: "PUBLISHED"throughPATCHskips that check, so prefer the dedicated route. - Publish and unpublish are idempotent and answer the article.
404 Article not found in this community for an id from elsewhere. Reading
published articles is articles.list() on the client (GET /articles).
Edit an event
Endpoint: PATCH /events/{idOrSlug}
Scope WRITE_EVENTS
Edit an event by its id (not its slug). Send any subset of name,
description, bannerUrl, cardImageUrl, startDate, endDate
(ISO 8601, start before end), timezone (IANA, for example
Europe/Lisbon), locations[] and physicalLocation.
| Status | Meaning |
|---|---|
400 No editable fields in request body | Nothing recognised. |
400 startDate must be before endDate | |
404 Event not found | Unknown id, or another community's event. |
Events that are live or have ended cannot be edited. For importers keyed on an external platform's id, use the event bridge.
Refund a sale (host side)
Endpoint: POST /sales/{saleId}/refund
Scope WRITE_SALES
The community refunds a buyer, for example after cancelling an event.
{ "reason": "Event cancelled", "refundType": "HOST_CANCELLATION", "amount": 15 }Unit quirk:
amounthere is in major units (15 means 15.00), not cents. Omit it for a full refund.
refundType is HOST_CANCELLATION (default), BUYER_REQUEST or
CHARGEBACK. The sale must have been sold by, or be for an event hosted by,
this community (403 otherwise, 404 when unknown). Payment processing
fees follow the platform refund policy. A buyer refunding their own purchase uses
events.refund() or products.refund() instead.
Subscriptions
Endpoints:
Scope WRITE_SUBSCRIPTIONS
- admin-cancel
{ targetUserId, reason? }cancels a member's paid membership.404 Subscription not foundwhen they have none. - change-tier
{ newSegmentId, billingCycle }moves a member to another tier. A free change applies at once and answers{ subscription }; a paid upgrade answers{ checkoutUrl }for the member to complete (send it to them, do not open it yourself).409when they are already on that tier.
A member changing their own tier uses me.membership.changeTier().
Elsewhere
Other server-side routes have their own pages:
- Signing members into an installed app and minting member tokens: App handoff.
- Onboarding for apps: Onboarding.
- Per-member app data and member language: App data.
- Approving and rejecting applications, the member roster: Members in the REST API.
- Notifications, feed posts and the event bridge: Content and Events.
- The community ledger: Finance and Report on finances.
- Reads with a personal user key: Member sessions and user keys.