Members
Methods of @cobuntu/embed for the signed-in member's account (me), tiers and applications, rules and the member roster. Setup, sessions and errors are on the
client overview; each method links to its endpoint in the
REST API reference.
me (session)
me.tickets
tickets({ when? })
Route: GET /me/tickets
Returns: Ticket[]
me.membership.get
membership.get()
Route: GET /me/membership
Returns: Membership or null
me.membership.checkout
membership.checkout({ segmentId, billingCycle, successUrl, cancelUrl })
Route: POST /me/membership/checkout
Returns: { checkoutUrl, sessionId }
me.membership.changeTier
membership.changeTier({ segmentId, billingCycle, successUrl, cancelUrl })
Route: POST /me/membership/change-tier
Returns: { status: "CHECKOUT_REQUIRED", checkoutUrl, sessionId } | { status: "CHANGED" | "SCHEDULED", membership }. Switching from a free tier cancels it first.
me.membership.cancel
membership.cancel()
Route: POST /me/membership/cancel
Returns: Membership (cancels at period end)
me.membership.reactivate
membership.reactivate()
Route: POST /me/membership/reactivate
Returns: Membership
me.membership.billingPortal
membership.billingPortal({ returnUrl })
Route: POST /me/membership/billing-portal
Returns: { url }
me.onboarding.get
onboarding.get()
Route: GET /me/onboarding
Returns: Onboarding
me.onboarding.data
onboarding.data({ segmentId, answers })
Route: POST /me/onboarding/data
Returns: Onboarding
me.onboarding.rules
onboarding.rules()
Route: POST /me/onboarding/rules
Returns: Onboarding
me.profile.get
profile.get()
Route: GET /me/profile
Returns: Profile
me.profile.update
profile.update({ name?, bio?, avatarUrl?, phone?, location?, locationVisibility?, languages?, hideFromDirectory?, usertag?, pronouns?, gender?, signature?, socials?, birthday?, emailVisibility?, phoneVisibility? })
Route: PATCH /me/profile
Returns: Profile. A taken usertag is 409 USERTAG_TAKEN with alternatives.
me.profile.events
profile.events()
Route: GET /me/profile/events
Returns: ProfileEvent[]: every event the member hosts, newest first, drafts included, each with catalogStatus (LIVE | PENDING | HIDDEN | REJECTED | DRAFT), catalogRejectionReason when declined with a reason, isDraft and draftStep. Only ever the caller's own rows.
me.profile.usertagAvailable
profile.usertagAvailable(usertag)
Route: GET /me/profile/usertag-available
Returns: { available, alternatives }. The member's own usertag counts as available; alternatives are already checked as free.
me.profile.avatar.upload
profile.avatar.upload(base64Image)
Route: PUT /me/profile/avatar
Returns: The new avatar URL. A png, jpeg or webp data URL up to 5 MB (INVALID_IMAGE, IMAGE_TOO_LARGE).
me.profile.avatar.remove
profile.avatar.remove()
Route: DELETE /me/profile/avatar
Returns: null
me.preferences.get / me.preferences.update
preferences.get() / .update({ locale?, timeFormat?, receivePromotionalContent?, notifications? })
Route: GET / PATCH /me/preferences
Returns: Preferences. notifications holds this community's email preferences and is merged on update.
me.password.change
password.change({ currentPassword, newPassword })
Route: POST /me/password
Returns: { ok, token }. Every session is signed out; store token as the new session.
me.export
export()
Route: GET /me/export
Returns: The account's data export as JSON
me.account.delete
account.delete({ password? })
Route: DELETE /me/account
Returns: { ok, status: "done" | "pending" }. Deletes the whole account, not only the membership.
me.friends.list
friends.list({ limit?, cursor? })
Route: GET /me/friends
Returns: { items: Friend[], nextCursor }
me.friends.remove
friends.remove(usertag)
Route: DELETE /me/friends/:usertag
Returns: undefined (204). FRIENDSHIP_NOT_FOUND
me.friends.requests.list
friends.requests.list(direction?)
Route: GET /me/friends/requests?direction=
Returns: FriendRequest[] ({ id, user, createdAt }), newest first. "incoming" (default) or "outgoing".
me.friends.requests.send
friends.requests.send(usertag)
Route: POST /me/friends/requests
Returns: "pending" | "accepted". Target must be a member here (MEMBER_NOT_FOUND). SELF_REQUEST, ALREADY_EXISTS
me.friends.requests.accept
friends.requests.accept(id)
Route: POST /me/friends/requests/:id/accept
Returns: "accepted". Receiver only; REQUEST_NOT_FOUND
me.friends.requests.decline
friends.requests.decline(id)
Route: POST /me/friends/requests/:id/decline
Returns: undefined (204). Receiver only
me.friends.requests.cancel
friends.requests.cancel(id)
Route: DELETE /me/friends/requests/:id
Returns: undefined (204). Your outgoing request
me.notifications.list
notifications.list({ limit?, cursor?, unread? })
Route: GET /me/notifications
Returns: { items: Notification[], nextCursor }: this community's rows plus friendship rows, newest first
me.notifications.unreadCount
notifications.unreadCount()
Route: GET /me/notifications/unread-count
Returns: number. Poll this.
me.notifications.markRead
notifications.markRead({ ids } | { all: true })
Route: POST /me/notifications/read
Returns: number of rows updated (within this community's scope)
me.notifications.muteThread / me.notifications.unmuteThread
notifications.muteThread(postId) / .unmuteThread(postId)
Route: POST / DELETE /me/notifications/mute-thread
Returns: boolean (muted)
me.referrals.get
referrals.get()
Route: GET /me/referrals
Returns: ReferralSummary: { programEnabled, payoutsConnected, link, links, joins, counts }
me.referrals.earnings
referrals.earnings()
Route: GET /me/referrals/earnings
Returns: ReferralEarnings: { totals, payments }, in cents
me.emails.list
emails.list()
Route: GET /me/emails
Returns: AccountEmail[], primary first
me.emails.add
emails.add(email)
Route: POST /me/emails
Returns: AccountEmail (unverified). INVALID_EMAIL, EMAIL_TAKEN, EMAIL_ALREADY_YOURS
me.emails.resendVerification
emails.resendVerification(id)
Route: POST /me/emails/:id/resend-verification
Returns: { sent: true }. EMAIL_NOT_FOUND, ALREADY_VERIFIED
me.emails.makePrimary
emails.makePrimary(id)
Route: POST /me/emails/:id/make-primary
Returns: AccountEmail. EMAIL_NOT_VERIFIED
me.emails.remove
emails.remove(id)
Route: DELETE /me/emails/:id
Returns: { removed: true }. REMOVE_PRIMARY
me.phone.sendOtp
phone.sendOtp(phoneNumber)
Route: POST /me/phone/send-otp
Returns: { sent: true }. E.164. INVALID_PHONE, RATE_LIMITED, PHONE_UNAVAILABLE
me.phone.verify
phone.verify({ phoneNumber, code })
Route: POST /me/phone/verify
Returns: { phoneNumber, phoneVerified: true }. INVALID_CODE, PHONE_TAKEN, OTP_THROTTLED
me.connectedAccounts.list
connectedAccounts.list()
Route: GET /me/connected-accounts
Returns: { accounts, google: { linked, email, connectedAt } }
me.connectedAccounts.google.link
connectedAccounts.google.link({ returnUrl, codeChallenge, state? })
Route: POST /me/connected-accounts/google/link
Returns: The Google URL (a string). RETURN_URL_NOT_ALLOWED
me.connectedAccounts.google.confirm
connectedAccounts.google.confirm({ code, codeVerifier })
Route: POST /me/connected-accounts/google/confirm
Returns: { linked: true, email }. Same session as link. INVALID_CODE, IDENTITY_TAKEN
me.connectedAccounts.google.unlink
connectedAccounts.google.unlink()
Route: DELETE /me/connected-accounts/google
Returns: { removed: true }. NOT_LINKED, LAST_CREDENTIAL
me.sellerVat.get / me.sellerVat.update
sellerVat.get() / .update({ vatRegistered?, vatCountry?, vatNumber? })
Route: GET / PUT /me/seller-vat
Returns: { vatRegistered, vatCountry, vatNumber }. INVALID_VAT_COUNTRY, VAT_NUMBER_REQUIRED
me.notes.list / me.notes.create / me.notes.delete
notes.list() / .create({ content, category? }) / .delete(id)
Route: GET / POST /me/notes, DELETE /me/notes/:id
Returns: Note[] / Note / undefined. Notes belong to the account and show in every community.
me.directory
directory({ q?, tier?, location?, language?, role?, cursor?, limit? })
Route: GET /me/directory
Returns: { members, facets, nextCursor }
me.member
member(usertag)
Route: GET /me/members/:usertag
Returns: MemberProfile: hostedEvents, plus signature, gender, friendsCount, mutualFriendsCount, friendship, friendRequestId, contact, notes
me.member.events
member.events(usertag)
Route: GET /me/members/:usertag/events
Returns: ProfileEvent[]: the member's live events here that the viewer may see
me.member.friends
member.friends(usertag, { limit?, cursor? })
Route: GET /me/members/:usertag/friends
Returns: { items: Friend[], nextCursor }
me.applications.list
applications.list()
Route: GET /me/applications
Returns: Application[]
me.applications.checkout
applications.checkout(requestId, { successUrl, cancelUrl })
Route: POST /me/applications/:requestId/checkout
Returns: { checkoutUrl, sessionId }
me.segments.apply
segments.apply(segmentId, { answers?, billingCycle?, currency?, source?, referralCode? })
Route: POST /me/segments/:segmentId/apply
Returns: { status: "JOINED" | "PENDING" | "PAYMENT_REQUIRED", ... }
me.reminderPreferences.get / me.reminderPreferences.update
reminderPreferences.get() / .update({ emailReminders })
Route: GET / PATCH /me/reminder-preferences
Returns: { emailReminders }
me.verifyEmailResend
verifyEmailResend()
Route: POST /me/verify-email/resend
Returns: { sent: true }
me.sales.refundEligibility
sales.refundEligibility(saleId)
Route: GET /me/sales/:saleId/refund-eligibility
Returns: { eligible, reason, windowEndsAt }
me.purchases
purchases({ limit?, offset? })
Route: GET /me/purchases
Returns: { purchases: Purchase[], total, hasMore }, newest first (limit 1-50)
me.purchaseDownload
purchaseDownload(saleId, attachmentId)
Route: GET /me/purchases/:saleId/attachments/:attachmentId/download
Returns: { url, expiresAt, maxDownloads, remainingDownloads }. The URL is signed for about 5 minutes; each call counts one download.
me.invoice
invoice(saleId)
Route: GET /me/sales/:saleId/invoice
Returns: The hosted invoice page URL (a string). INVOICE_NOT_AVAILABLE until issued.
me.receipt
receipt(saleId)
Route: GET /me/sales/:saleId/receipt
Returns: The receipt PDF as a Blob
me.events
events({ when?, role? })
Route: GET /me/events
Returns: { attending, attended, hosting, hosted }, each MemberEvent[]. A group excluded by when (upcoming | past) or role (attending | hosting) is [].
me.ledger
ledger({ type?, from?, to?, limit?, offset? })
Route: GET /me/ledger
Returns: { entries: LedgerEntry[], total, hasMore, summary }, newest first. type is purchase | refund | sale; limit 1-100, default 20.
me.library
library()
Route: GET /me/library
Returns: { items: LibraryItem[], total }: owned items with their downloads
segments (tiers) and apply
segments.public
segments.public()
Route: GET /segments/public
Returns: PublicSegment[] (prices per cadence, in cents)
segments.form
segments.form(segmentId, { invitationToken? })
Route: GET /segments/:segmentId/form
Returns: SegmentForm. A hidden tier needs its invitationToken.
segments.checkEmail
segments.checkEmail(segmentId, email)
Route: GET /segments/:segmentId/check-email
Returns: { status: "pending_application" | "existing_member" | "has_account" | "new" }
segments.submit
segments.submit(segmentId, { answers, invitationToken?, billingCycle?, currency? })
Route: POST /segments/:segmentId/submit
Returns: { success, requestId, paymentRequired?, autoApproved?, awaitingEmailConfirmation?, ... }. See Security model.
members.list
members.list({ usertags?, limit?, offset? })
Route: GET /members
Returns: { members: Member[], pagination }, newest accepted first. Follows the Members page setting: 403 MEMBERS_ONLY, 404 PAGE_DISABLED; the full roster needs a secret key with MEMBERS_ADMIN.
members.get
members.get(userIdOrUsertag)
Route: GET /members/:userId
Returns: Member. Same gate; a member hidden from the directory is 404 without MEMBERS_ADMIN.
members.membership
members.membership(userId)
Route: GET /members/:userId/membership
Returns: MemberMembership. permissions / segments only for a secret key with APP_ONBOARDING or MEMBERS_ADMIN.
apply.checkout
apply.checkout({ requestId, successUrl?, cancelUrl? })
Route: POST /apply/checkout
Returns: { checkoutUrl, sessionId }
rules
rules
rules()
Route: GET /rules
Returns: CommunityRule[]
v1 has no single-article route, so articles.get pages through the list 100 at a
time. Cache the answer if you call it on every request.