14 operations. Every schema and example on this page is generated from the platform contract.
How many recent events to return (default 100, max 200).
curl -G "https://www.membber.com/api/v1/board/activity" \
-H "Authorization: Bearer $MEMBBER_TOKEN"import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.GET("/api/v1/board/activity");
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.listBoardActivity().ok.body.json
print(response){
"activity": [
{
"id": 1,
"ticket_id": "fbc29b2e-0000-4000-8000-d0c5000000fb",
"actor": "<actor>",
"verb": "<verb>",
"detail": "<detail>",
"created_at": "<created_at>"
}
]
}How many candidates to return (default 12, max 50).
'founder-binding' when the founder has ranked it, else 'judgement'.
curl -G "https://www.membber.com/api/v1/board/candidates" \
-H "Authorization: Bearer $MEMBBER_TOKEN"import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.GET("/api/v1/board/candidates");
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.getBoardCandidates().ok.body.json
print(response){
"candidates": [
{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"title": "Morning class",
"type": "<type>",
"section": "<section>",
"epic_id": "a3ea3c95-0000-4000-8000-d0c5000000a3",
"prio": "<prio>",
"founder_ord": 1,
"founder_ranked": true,
"tier": "<tier>",
"unblocks_count": 1,
"age_days": 1,
"adjacent_to_inflight": true,
"branch": "<branch>",
"pr_number": 1
}
]
}The ticket to claim.
The claiming thread/session id (stamped on the row).
Who is picking it up.
Resolved column: the founder override (founder_col) if set, else the synced col.
The founder column override, or null when the item is not founder-pinned.
Resolved type: type_override if set, else the synced type.
Resolved priority: prio_override if set, else the synced prio.
Resolved title: display_title ?? title ?? raw_title.
ISO date (YYYY-MM-DD) the work landed / was raised.
ISO timestamp of the last sync write.
curl -X POST "https://www.membber.com/api/v1/board/claim" \
-H "Authorization: Bearer $MEMBBER_TOKEN" \
-H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678" \
-H "Content-Type: application/json" \
-d '{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"session": "<session>",
"assignee": "<assignee>"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/board/claim", {
body: {
id: "00000d1b-0000-4000-8000-d0c500000000",
session: "<session>",
assignee: "<assignee>"
},
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.claimBoardTicket(
body: .json(.init(
id: "00000d1b-0000-4000-8000-d0c500000000",
session: "<session>",
assignee: "<assignee>"
))
).ok.body.json
print(response){
"ticket": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"source": "<source>",
"pr_number": 1,
"branch": "<branch>",
"section": "<section>",
"col": "<col>",
"founder_col": "<founder_col>",
"pr_state": "<pr_state>",
"type": "<type>",
"prio": "<prio>",
"title": "Morning class",
"raw_title": "<raw_title>",
"summary": "<summary>",
"why": "<why>",
"what_it_does": "<what_it_does>",
"user_story": "<user_story>",
"epic_id": "a3ea3c95-0000-4000-8000-d0c5000000a3",
"when_ts": "<when_ts>",
"content_source": "<content_source>",
"synced_at": "<synced_at>",
"assignee": "<assignee>",
"claimed_at": "<claimed_at>",
"session_id": "630ddf64-0000-4000-8000-d0c500000063",
"depends_on": [
"<depends_on>"
],
"labels": [
"<label>"
],
"notes": "Added at the front desk",
"founder_ord": 1
}
}The ticket id this inbox item re-opens, or null for a fresh item.
'untriaged' or 'triaged'.
curl -G "https://www.membber.com/api/v1/board/inbox" \
-H "Authorization: Bearer $MEMBBER_TOKEN"import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.GET("/api/v1/board/inbox");
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.listBoardInbox().ok.body.json
print(response){
"inbox": [
{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"title": "Morning class",
"body": "<body>",
"section_hint": "<section_hint>",
"priority_hint": "<priority_hint>",
"reopen_of": "<reopen_of>",
"status": "<status>",
"created_at": "<created_at>",
"triaged_at": "<triaged_at>"
}
]
}The section to file this inbox item under.
The priority to assign to this inbox item.
The ticket id this inbox item re-opens, or null for a fresh item.
'untriaged' or 'triaged'.
curl -X POST "https://www.membber.com/api/v1/board/inbox/00000d1b-0000-4000-8000-d0c500000000/triage" \
-H "Authorization: Bearer $MEMBBER_TOKEN" \
-H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678" \
-H "Content-Type: application/json" \
-d '{
"section": "<section>",
"priority": "<priority>"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/board/inbox/{id}/triage", {
params: { path: { id: "00000d1b-0000-4000-8000-d0c500000000" } },
body: {
section: "<section>",
priority: "<priority>"
},
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.triageBoardInbox(
path: .init(id: "00000d1b-0000-4000-8000-d0c500000000"),
body: .json(.init(
section: "<section>",
priority: "<priority>"
))
).ok.body.json
print(response){
"inbox_item": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"title": "Morning class",
"body": "<body>",
"section_hint": "<section_hint>",
"priority_hint": "<priority_hint>",
"reopen_of": "<reopen_of>",
"status": "<status>",
"created_at": "<created_at>",
"triaged_at": "<triaged_at>"
}
}Verifies the email/password against Supabase auth, then checks the founder allowlist. On success mints a short-lived operator token. A correct password for a non-allow-listed address is a refusal (403), not a login.
The operator email (verified against Supabase auth).
The account password, verified against Supabase, never stored here.
The operator bearer token to send as Authorization: Bearer on every board call.
The verified, allow-listed operator email.
ISO timestamp the token expires.
curl -X POST "https://www.membber.com/api/v1/board/session" \
-H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678" \
-H "Content-Type: application/json" \
-d '{
"email": "alex@example.com",
"password": "<password>"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/board/session", {
body: {
email: "alex@example.com",
password: "<password>"
},
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.boardLogin(
body: .json(.init(
email: "alex@example.com",
password: "<password>"
))
).ok.body.json
print(response){
"token": "<token>",
"me": "<me>",
"expiresAt": "<expiresAt>"
}Verifies the Apple identity token fully (RS256 signature against Apple's JWKS, issuer, audience com.membber.hq, expiry), then checks the founder allowlist on the verified email. A missing / relay / non-allow-listed email is a 403 that echoes the email + Apple subject it saw, so the founder can add it. On success mints the same operator token.
The Sign in with Apple identity token (JWT) returned to the app.
The operator bearer token to send as Authorization: Bearer on every board call.
The verified, allow-listed operator email.
ISO timestamp the token expires.
curl -X POST "https://www.membber.com/api/v1/board/session/apple" \
-H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678" \
-H "Content-Type: application/json" \
-d '{
"identityToken": "<identityToken>"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/board/session/apple", {
body: {
identityToken: "<identityToken>"
},
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.boardLoginApple(
body: .json(.init(
identityToken: "<identityToken>"
))
).ok.body.json
print(response){
"token": "<token>",
"me": "<me>",
"expiresAt": "<expiresAt>"
}Verifies the Google ID token fully (RS256 signature against Google's JWKS via jwks-rsa, issuer accounts.google.com, audience the Membber Google client id, expiry) using the SAME production verifier the App Clip customer Google sign-in uses, src/lib/auth/googleAuth.ts verifyGoogleIdToken. Then checks the founder allowlist on the verified email. A missing / unverified / non-allow-listed email is a 403 that echoes the email + Google subject it saw, so the founder can add it. On success mints the same operator token.
The Google ID token (JWT) returned to the app.
The operator bearer token to send as Authorization: Bearer on every board call.
The verified, allow-listed operator email.
ISO timestamp the token expires.
curl -X POST "https://www.membber.com/api/v1/board/session/google" \
-H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678" \
-H "Content-Type: application/json" \
-d '{
"credential": "<credential>"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/board/session/google", {
body: {
credential: "<credential>"
},
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.boardLoginGoogle(
body: .json(.init(
credential: "<credential>"
))
).ok.body.json
print(response){
"token": "<token>",
"me": "<me>",
"expiresAt": "<expiresAt>"
}Filter to a resolved column (e.g. todo, doing, review, done, blocked).
Filter to a resolved type (bug, feature, task).
Filter to a section (payments, verticals, business, customer, platform).
Free-text match against title, raw title, why, id, branch and assignee.
Page size (default 50, max 200).
Opaque keyset cursor from a previous page.
Resolved column: the founder override (founder_col) if set, else the synced col.
The founder column override, or null when the item is not founder-pinned.
Resolved type: type_override if set, else the synced type.
Resolved priority: prio_override if set, else the synced prio.
Resolved title: display_title ?? title ?? raw_title.
ISO date (YYYY-MM-DD) the work landed / was raised.
ISO timestamp of the last sync write.
Cursor for the next page, or null when the list is exhausted.
curl -G "https://www.membber.com/api/v1/board/tickets" \
-H "Authorization: Bearer $MEMBBER_TOKEN"import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.GET("/api/v1/board/tickets");
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.listBoardTickets().ok.body.json
print(response){
"tickets": [
{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"source": "<source>",
"pr_number": 1,
"branch": "<branch>",
"section": "<section>",
"col": "<col>",
"founder_col": "<founder_col>",
"pr_state": "<pr_state>",
"type": "<type>",
"prio": "<prio>",
"title": "Morning class",
"raw_title": "<raw_title>",
"summary": "<summary>",
"why": "<why>",
"what_it_does": "<what_it_does>",
"user_story": "<user_story>",
"epic_id": "a3ea3c95-0000-4000-8000-d0c5000000a3",
"when_ts": "<when_ts>",
"content_source": "<content_source>",
"synced_at": "<synced_at>",
"assignee": "<assignee>",
"claimed_at": "<claimed_at>",
"session_id": "630ddf64-0000-4000-8000-d0c500000063",
"depends_on": [
"<depends_on>"
],
"labels": [
"<label>"
],
"notes": "Added at the front desk",
"founder_ord": 1
}
],
"next_cursor": "<next_cursor>"
}Resolved column: the founder override (founder_col) if set, else the synced col.
The founder column override, or null when the item is not founder-pinned.
Resolved type: type_override if set, else the synced type.
Resolved priority: prio_override if set, else the synced prio.
Resolved title: display_title ?? title ?? raw_title.
ISO date (YYYY-MM-DD) the work landed / was raised.
ISO timestamp of the last sync write.
Pre-denormalised media stored on the comment (may be empty).
curl -G "https://www.membber.com/api/v1/board/tickets/00000d1b-0000-4000-8000-d0c500000000" \
-H "Authorization: Bearer $MEMBBER_TOKEN"import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.GET("/api/v1/board/tickets/{id}", {
params: { path: { id: "00000d1b-0000-4000-8000-d0c500000000" } },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.getBoardTicket(
path: .init(id: "00000d1b-0000-4000-8000-d0c500000000")
).ok.body.json
print(response){
"ticket": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"source": "<source>",
"pr_number": 1,
"branch": "<branch>",
"section": "<section>",
"col": "<col>",
"founder_col": "<founder_col>",
"pr_state": "<pr_state>",
"type": "<type>",
"prio": "<prio>",
"title": "Morning class",
"raw_title": "<raw_title>",
"summary": "<summary>",
"why": "<why>",
"what_it_does": "<what_it_does>",
"user_story": "<user_story>",
"epic_id": "a3ea3c95-0000-4000-8000-d0c5000000a3",
"when_ts": "<when_ts>",
"content_source": "<content_source>",
"synced_at": "<synced_at>",
"assignee": "<assignee>",
"claimed_at": "<claimed_at>",
"session_id": "630ddf64-0000-4000-8000-d0c500000063",
"depends_on": [
"<depends_on>"
],
"labels": [
"<label>"
],
"notes": "Added at the front desk",
"founder_ord": 1
},
"comments": [
{
"id": "00000d1b-0000-4000-8000-d0c500000000",
"ticket_id": "fbc29b2e-0000-4000-8000-d0c5000000fb",
"author": "<author>",
"body": "<body>",
"media": [
{}
],
"created_at": "<created_at>"
}
],
"activity": [
{
"id": 1,
"ticket_id": "fbc29b2e-0000-4000-8000-d0c5000000fb",
"actor": "<actor>",
"verb": "<verb>",
"detail": "<detail>",
"created_at": "<created_at>"
}
]
}Partial overlay patch: a key PRESENT sets it (null clears the override), a key ABSENT is left untouched.
Founder title override; null clears it.
Full label set; null or omitted leaves it untouched.
Resolved column: the founder override (founder_col) if set, else the synced col.
The founder column override, or null when the item is not founder-pinned.
Resolved type: type_override if set, else the synced type.
Resolved priority: prio_override if set, else the synced prio.
Resolved title: display_title ?? title ?? raw_title.
ISO date (YYYY-MM-DD) the work landed / was raised.
ISO timestamp of the last sync write.
curl -X PATCH "https://www.membber.com/api/v1/board/tickets/00000d1b-0000-4000-8000-d0c500000000" \
-H "Authorization: Bearer $MEMBBER_TOKEN" \
-H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678" \
-H "Content-Type: application/json" \
-d '{
"overlay": {
"display_title": "<display_title>",
"notes": "Added at the front desk",
"type_override": "<type_override>",
"prio_override": "<prio_override>",
"epic_id": "a3ea3c95-0000-4000-8000-d0c5000000a3",
"labels": [
"<label>"
]
}
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.PATCH("/api/v1/board/tickets/{id}", {
params: { path: { id: "00000d1b-0000-4000-8000-d0c500000000" } },
body: {
overlay: {
display_title: "<display_title>",
notes: "Added at the front desk",
type_override: "<type_override>",
prio_override: "<prio_override>",
epic_id: "a3ea3c95-0000-4000-8000-d0c5000000a3",
labels: [
"<label>"
]
}
},
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.editBoardTicket(
path: .init(id: "00000d1b-0000-4000-8000-d0c500000000"),
body: .json(.init(
overlay: .init(
displayTitle: "<display_title>",
notes: "Added at the front desk",
typeOverride: "<type_override>",
prioOverride: "<prio_override>",
epicId: "a3ea3c95-0000-4000-8000-d0c5000000a3",
labels: ["<label>"]
)
))
).ok.body.json
print(response){
"ticket": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"source": "<source>",
"pr_number": 1,
"branch": "<branch>",
"section": "<section>",
"col": "<col>",
"founder_col": "<founder_col>",
"pr_state": "<pr_state>",
"type": "<type>",
"prio": "<prio>",
"title": "Morning class",
"raw_title": "<raw_title>",
"summary": "<summary>",
"why": "<why>",
"what_it_does": "<what_it_does>",
"user_story": "<user_story>",
"epic_id": "a3ea3c95-0000-4000-8000-d0c5000000a3",
"when_ts": "<when_ts>",
"content_source": "<content_source>",
"synced_at": "<synced_at>",
"assignee": "<assignee>",
"claimed_at": "<claimed_at>",
"session_id": "630ddf64-0000-4000-8000-d0c500000063",
"depends_on": [
"<depends_on>"
],
"labels": [
"<label>"
],
"notes": "Added at the front desk",
"founder_ord": 1
}
}Who owns it now; null unassigns.
Resolved column: the founder override (founder_col) if set, else the synced col.
The founder column override, or null when the item is not founder-pinned.
Resolved type: type_override if set, else the synced type.
Resolved priority: prio_override if set, else the synced prio.
Resolved title: display_title ?? title ?? raw_title.
ISO date (YYYY-MM-DD) the work landed / was raised.
ISO timestamp of the last sync write.
curl -X POST "https://www.membber.com/api/v1/board/tickets/00000d1b-0000-4000-8000-d0c500000000/assign" \
-H "Authorization: Bearer $MEMBBER_TOKEN" \
-H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678" \
-H "Content-Type: application/json" \
-d '{
"assignee": "<assignee>"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/board/tickets/{id}/assign", {
params: { path: { id: "00000d1b-0000-4000-8000-d0c500000000" } },
body: {
assignee: "<assignee>"
},
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.assignBoardTicket(
path: .init(id: "00000d1b-0000-4000-8000-d0c500000000"),
body: .json(.init(
assignee: "<assignee>"
))
).ok.body.json
print(response){
"ticket": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"source": "<source>",
"pr_number": 1,
"branch": "<branch>",
"section": "<section>",
"col": "<col>",
"founder_col": "<founder_col>",
"pr_state": "<pr_state>",
"type": "<type>",
"prio": "<prio>",
"title": "Morning class",
"raw_title": "<raw_title>",
"summary": "<summary>",
"why": "<why>",
"what_it_does": "<what_it_does>",
"user_story": "<user_story>",
"epic_id": "a3ea3c95-0000-4000-8000-d0c5000000a3",
"when_ts": "<when_ts>",
"content_source": "<content_source>",
"synced_at": "<synced_at>",
"assignee": "<assignee>",
"claimed_at": "<claimed_at>",
"session_id": "630ddf64-0000-4000-8000-d0c500000063",
"depends_on": [
"<depends_on>"
],
"labels": [
"<label>"
],
"notes": "Added at the front desk",
"founder_ord": 1
}
}The comment text (non-empty).
Optional pre-uploaded media descriptors to denormalise onto the comment.
Client-generated idempotency key (same pattern as the messaging architecture's client_message_id). A retry with the same key on the same ticket is a no-op that returns the ORIGINAL comment, never a duplicate, this route is declared idempotency:{mode:"rpc"}, which board_comment now actually enforces.
Pre-denormalised media stored on the comment (may be empty).
curl -X POST "https://www.membber.com/api/v1/board/tickets/00000d1b-0000-4000-8000-d0c500000000/comments" \
-H "Authorization: Bearer $MEMBBER_TOKEN" \
-H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678" \
-H "Content-Type: application/json" \
-d '{
"body": "<body>"
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/board/tickets/{id}/comments", {
params: { path: { id: "00000d1b-0000-4000-8000-d0c500000000" } },
body: {
body: "<body>"
},
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.commentBoardTicket(
path: .init(id: "00000d1b-0000-4000-8000-d0c500000000"),
body: .json(.init(
body: "<body>"
))
).ok.body.json
print(response){
"comment": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"ticket_id": "fbc29b2e-0000-4000-8000-d0c5000000fb",
"author": "<author>",
"body": "<body>",
"media": [
{}
],
"created_at": "<created_at>"
}
}The founder can only move an item to To-do or Blocked; threads advance the rest.
todoblockedFractional sort index within the target column.
Resolved column: the founder override (founder_col) if set, else the synced col.
The founder column override, or null when the item is not founder-pinned.
Resolved type: type_override if set, else the synced type.
Resolved priority: prio_override if set, else the synced prio.
Resolved title: display_title ?? title ?? raw_title.
ISO date (YYYY-MM-DD) the work landed / was raised.
ISO timestamp of the last sync write.
curl -X POST "https://www.membber.com/api/v1/board/tickets/00000d1b-0000-4000-8000-d0c500000000/move" \
-H "Authorization: Bearer $MEMBBER_TOKEN" \
-H "Idempotency-Key: 1f0e2d3c-4b5a-4678-9abc-def012345678" \
-H "Content-Type: application/json" \
-d '{
"col": "todo",
"ord": 1
}'import { createMembberClient } from "@membber/sdk-ts";
const membber = createMembberClient({
getAccessToken: () => process.env.MEMBBER_TOKEN,
});
const { data, error } = await membber.raw.POST("/api/v1/board/tickets/{id}/move", {
params: { path: { id: "00000d1b-0000-4000-8000-d0c500000000" } },
body: {
col: "todo",
ord: 1
},
headers: { "Idempotency-Key": crypto.randomUUID() },
});
if (error) {
// Typed error envelope: { error: { code, message, requestId } }
throw new Error(`${error.error.code}: ${error.error.message}`);
}
console.log(data);import MembberSwift
let client = MembberClient(
serverURL: MembberClient.productionServerURL,
tokenProvider: { session.accessToken }
)
let response = try await client.api.moveBoardTicket(
path: .init(id: "00000d1b-0000-4000-8000-d0c500000000"),
body: .json(.init(
col: .todo,
ord: 1
))
).ok.body.json
print(response){
"ticket": {
"id": "00000d1b-0000-4000-8000-d0c500000000",
"source": "<source>",
"pr_number": 1,
"branch": "<branch>",
"section": "<section>",
"col": "<col>",
"founder_col": "<founder_col>",
"pr_state": "<pr_state>",
"type": "<type>",
"prio": "<prio>",
"title": "Morning class",
"raw_title": "<raw_title>",
"summary": "<summary>",
"why": "<why>",
"what_it_does": "<what_it_does>",
"user_story": "<user_story>",
"epic_id": "a3ea3c95-0000-4000-8000-d0c5000000a3",
"when_ts": "<when_ts>",
"content_source": "<content_source>",
"synced_at": "<synced_at>",
"assignee": "<assignee>",
"claimed_at": "<claimed_at>",
"session_id": "630ddf64-0000-4000-8000-d0c500000063",
"depends_on": [
"<depends_on>"
],
"labels": [
"<label>"
],
"notes": "Added at the front desk",
"founder_ord": 1
}
}