Works
Works, steps and brand tasks.
Privacy and analytics
We use necessary technical cookies and, only with your consent, analytics and marketing pixels to improve the website and measure campaigns.
Works, steps and brand tasks.
Works of the brand with the product each comes from, status, progress and how many tasks wait for the brand. A work is a larger job with several steps; a task is one bounded step. query matches the title or the product name ("Post" finds every Post, however it was renamed).
| Field | Value |
|---|---|
| Kind | Read |
| HTTP method | POST /api/v1/works.list |
| MCP tool | works_list |
| Scope | works.read |
| Minimum role | Viewer |
| Human confirmation | No |
| Doors | Nödo, Voice, MCP, API, Chat, Screens, Apps |
| Status | Available |
| Widget | list |
Input
{
status?: "active" | "finished" | "archived" | "all" // default "active"
query?: string // ≤ 120 · Words in the work title or its product name.
cursor?: string // ≤ 512 · Opaque cursor from a previous `nextCursor`.
limit?: integer // 1–50 · default 20
}Output
{
items: Array<{
id: string // uuid
name: string // The title; people may rename it, and some follow their content (a Post takes its first words).
productName: string | null // The product the work comes from («Post», «Plan de contenidos · Esencial»); it never changes. Null for older works without one.
status: string
statusCategory: "triage" | "backlog" | "unstarted" | "started" | "paused" | "completed" | "canceled" // Where the work stands in Nömad's status registry: unstarted, started, paused, completed or canceled.
dueDate: string | null
progress: {
done: integer // -9007199254740991–9007199254740991
total: integer // -9007199254740991–9007199254740991
}
waitingOnBrand: integer // -9007199254740991–9007199254740991 · Tasks waiting for the brand.
}>
nextCursor: string | null
}One work with its steps and who holds each one. detailed adds deliverables and answers; keep concise unless you need them.
| Field | Value |
|---|---|
| Kind | Read |
| HTTP method | POST /api/v1/works.get |
| MCP tool | works_get |
| Scope | works.read |
| Minimum role | Viewer |
| Human confirmation | No |
| Doors | Nödo, Voice, MCP, API, Chat, Screens, Apps |
| Status | Available |
| Widget | record |
Input
{
workId: string // uuid
format?: "concise" | "detailed" // default "concise" · `concise` returns names and states only; `detailed` adds ids and full fields.
}Output
{
id: string // uuid
name: string // The title; people may rename it, and some follow their content (a Post takes its first words).
productName: string | null // The product the work comes from («Post», «Plan de contenidos · Esencial»); it never changes. Null for older works without one.
status: string
statusCategory: "triage" | "backlog" | "unstarted" | "started" | "paused" | "completed" | "canceled" // Where the work stands in Nömad's status registry: unstarted, started, paused, completed or canceled.
dueDate: string | null
progress: {
done: integer // -9007199254740991–9007199254740991
total: integer // -9007199254740991–9007199254740991
}
waitingOnBrand: integer // -9007199254740991–9007199254740991 · Tasks waiting for the brand.
steps: Array<{
id: string // uuid
title: string
status: string // The brand-facing state: waiting_on_brand, waiting_on_brand_review, in_progress, blocked, upcoming, done, canceled or info.
statusCategory: "triage" | "backlog" | "unstarted" | "started" | "paused" | "completed" | "canceled" // The same task in Nömad's status registry (unstarted, started, paused, completed, canceled).
kind: "questionnaire" | "files" | "review" | "information"
dueDate: string | null
owner: "brand" | "nomad"
}>
}Tasks waiting for the brand across all works, most urgent first. Use it to answer "what do I have pending?".
| Field | Value |
|---|---|
| Kind | Read |
| HTTP method | POST /api/v1/works.tasks.pending |
| MCP tool | works_tasks_pending |
| Scope | works.read |
| Minimum role | Viewer |
| Human confirmation | No |
| Doors | Nödo, Voice, MCP, API, Chat, Screens, Apps |
| Status | Available |
| Widget | list |
Input
{
cursor?: string // ≤ 512 · Opaque cursor from a previous `nextCursor`.
limit?: integer // 1–50 · default 20
}Output
{
items: Array<{
id: string // uuid
workId: string // uuid
workName: string
title: string
status: string // The brand-facing state: waiting_on_brand, waiting_on_brand_review, in_progress, blocked, upcoming, done, canceled or info.
statusCategory: "triage" | "backlog" | "unstarted" | "started" | "paused" | "completed" | "canceled" // The same task in Nömad's status registry (unstarted, started, paused, completed, canceled).
kind: "questionnaire" | "files" | "review" | "information"
dueDate: string | null
}>
nextCursor: string | null
}One task with its questionnaire (the snapshot contracted with the work), saved draft answers and deliverables to review.
| Field | Value |
|---|---|
| Kind | Read |
| HTTP method | POST /api/v1/works.tasks.get |
| MCP tool | works_tasks_get |
| Scope | works.read |
| Minimum role | Viewer |
| Human confirmation | No |
| Doors | Nödo, Voice, MCP, API, Chat, Screens, Apps |
| Status | Available |
| Widget | record |
Input
{
taskId: string // uuid
}Output
{
id: string // uuid
workId: string // uuid
workName: string
title: string
status: string // The brand-facing state: waiting_on_brand, waiting_on_brand_review, in_progress, blocked, upcoming, done, canceled or info.
statusCategory: "triage" | "backlog" | "unstarted" | "started" | "paused" | "completed" | "canceled" // The same task in Nömad's status registry (unstarted, started, paused, completed, canceled).
kind: "questionnaire" | "files" | "review" | "information"
dueDate: string | null
questions: Array<{
id: string
label: string
type: string
required: boolean
options?: string[]
}>
draft: Array<{
questionId: string
value: string | number | boolean | string[]
}>
deliverables: Array<{
assetId: string // uuid
name: string
version: integer // -9007199254740991–9007199254740991
}>
revision: integer // -9007199254740991–9007199254740991
}Saves questionnaire answers. With submit: true the task is handed in and the work advances, which asks for confirmation.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.tasks.answer |
| MCP tool | works_tasks_answer |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | Yes |
| Doors | Nödo, MCP, API, Chat, Screens, Apps |
| Status | Available |
| Widget | confirm |
Input
{
taskId: string // uuid
expectedRevision: integer // -9007199254740991–9007199254740991
answers: Array<{
questionId: string
value: string | number | boolean | string[]
}> // ≤ 100 items
submit?: boolean // default false
}Output
{
ok: true
id?: string
revision?: integer // -9007199254740991–9007199254740991
}Approves a deliverable or requests changes with a comment. Only for review tasks that are waiting for the brand; the task status is checked server-side.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.tasks.review |
| MCP tool | works_tasks_review |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | Yes |
| Doors | Nödo, MCP, API, Chat, Screens, Apps |
| Status | Available |
| Widget | confirm |
Input
{
decision: "approve"
taskId: string // uuid
expectedRevision: integer // -9007199254740991–9007199254740991
}
| {
decision: "request_changes"
taskId: string // uuid
expectedRevision: integer // -9007199254740991–9007199254740991
comment: string // ≤ 4000
}Output
{
ok: true
id?: string
revision?: integer // -9007199254740991–9007199254740991
}Saves the answers agreed in a «Briefing with Nödo» conversation as the answers of that task and hands it in, so the work moves on. Call it once, when every required question has an answer the person agreed; lists go as arrays. The person accepts the summary on the card or edits it in the form. It never writes brand memory: durable learnings are proposed when the work closes.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.briefing.accept |
| MCP tool | works_briefing_accept |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | Yes |
| Doors | Nödo, Chat, Screens, Apps |
| Status | Available |
| Widget | confirm |
Input
{
taskId: string // uuid
expectedRevision: integer // -9007199254740991–9007199254740991
answers: Array<{
questionId: string
value: string | number | boolean | string[]
}> // ≤ 100 items
}Output
{
ok: true
id?: string
revision?: integer // -9007199254740991–9007199254740991
}Approves the editorial plan of a work. rhythm accepts the weekly rhythm (kept with the recurring plan and reused every month); month approves the month and writes each slot (date and time, network, format, one-line idea) into its publication task as a draft with a proposed time. It never publishes or schedules for real: each post goes out only once someone schedules it in its task. expectedRevision is the board revision the person saw.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.editorial_plan.approve |
| MCP tool | works_editorial_plan_approve |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | Yes |
| Doors | Nödo, Chat, Screens, Apps |
| Status | Available |
| Widget | confirm |
Input
{
taskId: string // uuid
expectedRevision: integer // 0–9007199254740991
part: "rhythm" | "month"
}Output
{
ok: true
id?: string
revision?: integer // -9007199254740991–9007199254740991
}Starts a work from a Store product the brand may start without paying (free or included in its plan), with all its steps; the person confirms on a card first. Use it when a request is something the Store sells (a post, a logo, a web, a naming…): find the product with store_products_search or store_recommendations_list first and only call this for one marked includedInPlan. For a paid product it returns the Store page link instead; it never charges.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.create_from_product |
| MCP tool | works_create_from_product |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | Yes |
| Doors | Nödo, MCP, API, Chat, Screens, Apps |
| Status | Available |
| Widget | confirm |
Input
{
productSlug: string // ≤ 120 · Slug from store_products_search or store_recommendations_list.
originConversationId?: string // uuid · Set by Nödo itself; leave it out.
}Output
{
ok: true
id: string // uuid
name: string
url: string // uri · The new work in the app.
}
| {
ok: false
reason: "not_in_plan"
storeUrl: string // uri
}The plain-form side of «Briefing with Nödo», the same acceptance as works.briefing.accept: answers keyed by question id become the task's answers and the work moves on. Only the work's approver (or the Nömad team). Writes no brand memory.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.briefing.submit_form |
| MCP tool | works_briefing_submit_form |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
taskId: string // uuid
answers: Record<string, string>
}Output
{
ok: true
}Adds a step of the brand's own at the end of a work and returns it. A work bought in the Store follows its product's plan and refuses added steps (invalid_input, detail storePurchase).
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.tasks.create |
| MCP tool | works_tasks_create |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
workId: string // uuid
title: string // ≤ 10000
description?: string | null // default null
dueDate?: string | null // default null
}Output
{
task: {
id: string // uuid
work_id: string // uuid
brand_id: string // uuid
title: string
}
}Deletes a step the caller added to a work themselves (never the steps Nömad planned). Whoever may add steps may delete the ones they created. Soft delete: works.tasks.restore_own puts it back within ten minutes.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.tasks.trash_own |
| MCP tool | works_tasks_trash_own |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | Yes |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
taskId: string // uuid
}Output
{
ok: true
}Puts back an own step the same person removed less than ten minutes ago (invalid_input, detail undoExpired, after that).
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.tasks.restore_own |
| MCP tool | works_tasks_restore_own |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
taskId: string // uuid
}Output
{
ok: true
}Saves what the brand writes into its own step (text, already uploaded files, checklist and questionnaire answers). With final: true it hands the step in: it is marked done and the work moves on. Only open steps of the brand accept input.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.tasks.input.save |
| MCP tool | works_tasks_input_save |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | Yes |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
taskId: string // uuid
final?: boolean // default false
data: {
client_text?: string | null
client_files?: string[] // ≤ 30 items
client_items?: Array<{
text: string // ≤ 2000
checked: boolean
}> // ≤ 100 items
client_answers?: Record<string, string>
}
}Output
{
ok: true
}Before uploading a file to a work step: checks the step belongs to the brand and the bytes fit the plan and 50 MB, reserves them and returns a single-use signed upload URL for a server-chosen path in the step folder. Upload with HTTP PUT, then call works.tasks.files.register with storagePath.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.tasks.files.prepare |
| MCP tool | works_tasks_files_prepare |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | No |
| Doors | Screens, Apps, API |
| Status | Available |
Input
{
taskId: string // uuid
fileName: string // ≤ 255
fileSize: integer // –52428800
mimeType?: string // ≤ 255
}Output
{
storagePath: string
uploadUrl: string // uri
token: string
}A problem with a work step: a person's report (user_report) becomes a feedback ticket support answers; a step type the app cannot draw yet (unknown_module) opens one deduplicated ticket per person and step and alerts the team with platform and version.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.tasks.report_issue |
| MCP tool | works_tasks_report_issue |
| Scope | works.write |
| Minimum role | Viewer |
| Human confirmation | No |
| Doors | Screens, Apps, API |
| Status | Available |
Input
{
workId: string // uuid
taskId: string // uuid
reason: "user_report" | "unknown_module"
moduleType?: string | null
message?: string | null
platform?: "ios" | "android" | "mac" | "web" // default "ios"
appVersion?: string | null
}Output
{
ticketId: string | null
deduplicated: boolean
}Registers a file already uploaded into the task's folder (<brand>/task-files/<task>/) on the step and in the brand's Library. It never fetches a URL. The step's file rules are checked before anything is stored, so a refused file never reaches the Library: conflict with files_not_accepted (the step takes no files), unsupported_media or file_too_large (no place of the step takes that type or size).
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.tasks.files.register |
| MCP tool | works_tasks_files_register |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
taskId: string // uuid
storagePath: string // ≤ 1024
fileName: string // ≤ 255
fileSize: integer // –52428800
mimeType?: string // ≤ 255
}Output
{
url: string
fileName: string
fileSize: number
mimeType: string
}Detaches one file from the brand's step. The file itself stays in the brand's Library.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.tasks.files.remove |
| MCP tool | works_tasks_files_remove |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
taskId: string // uuid
fileUrl: string // ≤ 2048
}Output
{
ok: true
}The approver's decision on a delivery waiting for the brand's review: approve it (the step closes and the work advances) or request changes with a comment, the files of the comment's draft folder and «+» cards. In a work where everyone must approve, partial says who is still to approve.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.tasks.decide |
| MCP tool | works_tasks_decide |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | Yes |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
decision: "approve"
taskId: string // uuid
}
| {
decision: "request_changes"
taskId: string // uuid
comment: string // ≤ 20000
extras?: {
draftId?: string
attachments?: unknown
inserts?: unknown
}
}Output
{
ok: true
partial: {
approved: integer // -9007199254740991–9007199254740991
required: integer // -9007199254740991–9007199254740991
waitingFor: string[]
}
| null
}Deletes a file uploaded into the draft folder of a «request changes» comment before it is sent, unless a saved comment already holds it. Only the work's approver, while the delivery waits for review.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.tasks.comment_files.discard |
| MCP tool | works_tasks_comment_files_discard |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
taskId: string // uuid
draftId: string // uuid
path: string // ≤ 600
}Output
{
ok: true
}Starts a Store product as a work and returns it with its steps. Free or plan-included products start at once; with priceId (a one-time priced product) it starts now and is paid inside the work, which needs whoever manages the brand's plan. Recurring products keep their subscription checkout.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.start_from_store |
| MCP tool | works_start_from_store |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | No |
| Doors | API, Screens, Apps |
| Status | Available |
Input
{
productId: string // ≤ 120
checkoutAttemptId?: string // ≤ 120
priceId?: string // ≤ 120
extras?: Array<{
lineKey: string // ≤ 200
quantity: integer // -9007199254740991–9007199254740991
}> // ≤ 50 items
originConversationId?: string // uuid
}Output
{
workId: string // uuid
work: {
id: string // uuid
name: string
}
| null
taskError: string | null
}Once no brand question blocks a work, lets it continue: resolves its steps (a manual work only clears the old wait). Answers error: questions_pending while a required question is still open; it never takes prompts or answers.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.questions.complete |
| MCP tool | works_questions_complete |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
workId: string // uuid
}Output
{
taskCount: integer // -9007199254740991–9007199254740991
error: string | null
}Archives a work (it leaves the active list) or brings it back. Asking for the state it already has changes nothing.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.set_archived |
| MCP tool | works_set_archived |
| Scope | works.write |
| Minimum role | Admin |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
workId: string // uuid
archived: boolean
}Output
{
work: {
id: string // uuid
archived_at: string | null
archived_by: string | null
}
}Pins a work's title, or clears it so the title follows its content again (invalid_input, detail title_required, for a work that cannot follow its content). The product name next to it never changes.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.set_title |
| MCP tool | works_set_title |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
workId: string // uuid
title: string // ≤ 2000
}Output
{
title: string
source: "manual" | "auto"
}Pins a task's title, or clears it so the title follows its content again (invalid_input, detail title_required, when it cannot).
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.tasks.set_title |
| MCP tool | works_tasks_set_title |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
taskId: string // uuid
title: string // ≤ 2000
}Output
{
title: string
source: "manual" | "auto"
}Replaces who approves a work on one side (client: the brand, owners and admins decide; internal: Nömad, one person); an empty list returns that side to its default. Whoever is added hears it, with every delivery already waiting. Returns the approvers view.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.approvers.set |
| MCP tool | works_approvers_set |
| Scope | works.write |
| Minimum role | Viewer |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
workId: string // uuid
role: "client" | "internal"
approvers: Array<{
userId: string // uuid
required?: boolean // default true
defaultSource?: "manual" | "requester" | "brand_manager" // default "manual"
}> // ≤ 5 items
}Output
{
viewerId?: string | null
canEdit: {
client: boolean
internal: boolean
}
}For the brand's side of a work: one approval is enough (any) or everyone must approve (all). Deliveries already waiting follow the new mode from their next approval; nobody is notified.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.approvers.set_mode |
| MCP tool | works_approvers_set_mode |
| Scope | works.write |
| Minimum role | Viewer |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
workId: string // uuid
mode: "any" | "all"
}Output
{
viewerId?: string | null
canEdit: {
client: boolean
internal: boolean
}
}Creates the draft post of a «Publication» step the first time its performer opens it (the brand for its own step, Nömad for Nömad's), then always returns the same one. It never publishes or schedules.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.tasks.publication.start_draft |
| MCP tool | works_tasks_publication_start_draft |
| Scope | works.write |
| Minimum role | Viewer |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
taskId: string // uuid
}Output
{
postId: string // uuid
}Saves a new immutable revision of one output of a running component (text, files from the Library, link). The brand only submits components whose responsibility is the client's; idempotencyKey makes a retry return the same revision.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.execution.outputs.submit |
| MCP tool | works_execution_outputs_submit |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
taskId: string // uuid
outputKey: string
payload: Record<string, unknown>
idempotencyKey: string // uuid
}Output
{
work_id: string
}Approves or rejects (with feedback) one component output; the work execution then continues with whatever comes next.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.execution.outputs.review |
| MCP tool | works_execution_outputs_review |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | Yes |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
outputId: string // uuid
decision: "approved" | "rejected"
feedback?: string // ≤ 4000
}Output
{
work_id: string
}Saves the answers of a work's execution brief (expectedVersion is the version the person saw) and lets the work continue.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.execution.brief.save |
| MCP tool | works_execution_brief_save |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
workId: string // uuid
answers: Record<string, unknown>
expectedVersion: integer // 0–9007199254740991
}Output
{
work_id: string
}Moves a work's execution forward; with retryTaskId it first retries that failed component.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.execution.resume |
| MCP tool | works_execution_resume |
| Scope | works.write |
| Minimum role | Member |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
workId: string // uuid
retryTaskId?: string // uuid
}Output
{
ok: true
}Sets which actions the execution of a product's works may take on its own on the brand's connections (create a draft, schedule, publish, send).
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.execution.policy.set |
| MCP tool | works_execution_policy_set |
| Scope | works.write |
| Minimum role | Admin |
| Human confirmation | No |
| Doors | API, Screens, Apps |
| Status | Available |
Input
{
productId: string // uuid
enabled: boolean
allowedActions: Array<{
integrationProductId: string // uuid
operation: "create_draft" | "schedule" | "publish" | "send"
integrationId: string // uuid
}> // ≤ 50 items
}Output
{
product_id: string
enabled: boolean
}Pauses or resumes the execution of a contract and sets when it starts and ends.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.execution.calendar.set |
| MCP tool | works_execution_calendar_set |
| Scope | works.write |
| Minimum role | Admin |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
contractId: string // uuid
paused: boolean
startsAt: string | null
endsAt: string | null
}Output
{
ok: true
}What a work's payment step asks for (amount with tax, deposit or rest, state), whether the caller may pay it, and for a deposit whether the rest will be charged automatically with the same card (autopay). Paying runs works.payments.start.
| Field | Value |
|---|---|
| Kind | Read |
| HTTP method | POST /api/v1/works.payments.get |
| MCP tool | works_payments_get |
| Scope | works.read |
| Minimum role | Billing |
| Human confirmation | No |
| Doors | Screens, Apps, API |
| Status | Available |
Input
{
taskId: string // uuid
}Output
{
summary: {
taskId: string
workId: string
state: string
title?: string
kind?: "partial" | "final"
percentBps?: integer | null
grossMinor?: integer // -9007199254740991–9007199254740991
currency?: string
remainingMinor?: integer // -9007199254740991–9007199254740991
}
canPay: boolean
autopay: {
available: boolean // A deposit with a later payment step in the same work.
enabled: boolean // The rest will be charged off-session with the card of this deposit.
suggested: boolean // On by default: the brand pays itself.
decided: boolean // Someone already chose on or off for this deposit.
}
| null
}Prepares the PaymentIntent of a work's payment step (the amount always comes from the server) for the person to confirm with Stripe. Only whoever pays for the brand.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.payments.start |
| MCP tool | works_payments_start |
| Scope | works.write |
| Minimum role | Billing |
| Human confirmation | No |
| Doors | Screens, Apps |
| Status | Available |
Input
{
taskId: string // uuid
autopayRest?: "on" | "off" | "suggested"
}Output
{
summary: {
taskId: string
workId: string
state: string
title?: string
kind?: "partial" | "final"
percentBps?: integer | null
grossMinor?: integer // -9007199254740991–9007199254740991
currency?: string
remainingMinor?: integer // -9007199254740991–9007199254740991
}
clientSecret: string | null
publishableKey: string
sheet?: {
publishableKey: string
customerId: string | null
customerSessionClientSecret: string | null
merchantCountryCode: "ES"
merchantDisplayName: string
googlePayEnvironment: "test" | "production"
}
| null
autopay?: {
available: boolean // A deposit with a later payment step in the same work.
enabled: boolean // The rest will be charged off-session with the card of this deposit.
suggested: boolean // On by default: the brand pays itself.
decided: boolean // Someone already chose on or off for this deposit.
}
| null
}After the person confirms in Stripe, re-reads the payment on the server and closes the step when it is paid.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.payments.confirm |
| MCP tool | works_payments_confirm |
| Scope | works.write |
| Minimum role | Billing |
| Human confirmation | No |
| Doors | Screens, Apps |
| Status | Available |
Input
{
taskId: string // uuid
}Output
{
taskId: string
workId: string
state: string
title?: string
kind?: "partial" | "final"
percentBps?: integer | null
grossMinor?: integer // -9007199254740991–9007199254740991
currency?: string
remainingMinor?: integer // -9007199254740991–9007199254740991
}Nömad team only: creates a payment link for a step, valid for 30 days, that pays without an account; the amount is recomputed when it is opened.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.payments.send_link |
| MCP tool | works_payments_send_link |
| Scope | works.write |
| Minimum role | Billing |
| Human confirmation | No |
| Doors | API, Screens, Apps |
| Status | Available |
Input
{
taskId: string // uuid
}Output
{
url: string
expiresAt: string
summary: {
taskId: string
workId: string
state: string
title?: string
kind?: "partial" | "final"
percentBps?: integer | null
grossMinor?: integer // -9007199254740991–9007199254740991
currency?: string
remainingMinor?: integer // -9007199254740991–9007199254740991
}
}Nömad team only: records a payment received outside Stripe (transfer, cash, card terminal). Same ledger and same step closure; idempotencyKey makes a retry harmless.
| Field | Value |
|---|---|
| Kind | Write |
| HTTP method | POST /api/v1/works.payments.register |
| MCP tool | works_payments_register |
| Scope | works.write |
| Minimum role | Billing |
| Human confirmation | No |
| Doors | API, Screens, Apps |
| Status | Available |
Input
{
taskId: string // uuid
method: "transfer" | "cash" | "card_terminal" | "other"
reference: string | null
receivedOn: string | null
idempotencyKey: string // uuid
}Output
{
taskId: string
workId: string
state: string
title?: string
kind?: "partial" | "final"
percentBps?: integer | null
grossMinor?: integer // -9007199254740991–9007199254740991
currency?: string
remainingMinor?: integer // -9007199254740991–9007199254740991
}The brand's works in progress with their visible steps (and, for a «Post» work, where its post is), the archived ones, the person's pins and order: what the «Works» sidebar lists. Catalogue test runs only for Nömad staff.
| Field | Value |
|---|---|
| Kind | Read |
| HTTP method | POST /api/v1/works.sidebar |
| MCP tool | works_sidebar |
| Scope | works.read |
| Minimum role | Viewer |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
timeZone?: string | null
asClient?: boolean // Read as the brand sees it (a staff viewer previewing as client). Only narrows.
}Output
{
works: Array<{
id: string
name: string
status: string | null
color: string | null
due_date: string | null
is_recurring: boolean | null
recurring_interval: string | null
archived_at: string | null
archived_by: string | null
product_name?: string | null // The product the work comes from, in the reader's language.
product_icon?: string | null // The product's icon name (`products.icon`): the kind-of-work glyph lists draw.
updated_at?: string | null
created_at?: string | null
approvalElsewhere?: boolean // Someone else approves this work: its approval steps are not the reader's to act on.
tasks?: Array<{
id: string
title: string
status: string | null
task_type?: string | null
module_type?: string | null
step_kind?: string | null
artifact_type?: string | null
completion_mode?: string | null
due_date?: string | null
max_days?: number | null
created_at?: string | null
post?: {
chip: string // Where the step's post is, as the Posts list says it: draft, in_review, approved_unscheduled, scheduled, sending, manual_pending, attention, published, deleted, cancelled or unconnected.
scheduledAt: string | null // The next time one of its destinations goes out (ISO), when one is scheduled.
}
| null // Only on the single «Publicación» step of a «Post» work whose draft exists.
}>
}>
archived: Array<{
id: string
name: string
status: string | null
color: string | null
due_date: string | null
is_recurring: boolean | null
recurring_interval: string | null
archived_at: string | null
archived_by: string | null
product_name?: string | null // The product the work comes from, in the reader's language.
product_icon?: string | null // The product's icon name (`products.icon`): the kind-of-work glyph lists draw.
updated_at?: string | null
created_at?: string | null
approvalElsewhere?: boolean // Someone else approves this work: its approval steps are not the reader's to act on.
tasks?: Array<{
id: string
title: string
status: string | null
task_type?: string | null
module_type?: string | null
step_kind?: string | null
artifact_type?: string | null
completion_mode?: string | null
due_date?: string | null
max_days?: number | null
created_at?: string | null
post?: {
chip: string // Where the step's post is, as the Posts list says it: draft, in_review, approved_unscheduled, scheduled, sending, manual_pending, attention, published, deleted, cancelled or unconnected.
scheduledAt: string | null // The next time one of its destinations goes out (ISO), when one is scheduled.
}
| null // Only on the single «Publicación» step of a «Post» work whose draft exists.
}>
}>
completed?: Array<{
id: string
name: string
status: string | null
color: string | null
due_date: string | null
is_recurring: boolean | null
recurring_interval: string | null
archived_at: string | null
archived_by: string | null
product_name?: string | null // The product the work comes from, in the reader's language.
product_icon?: string | null // The product's icon name (`products.icon`): the kind-of-work glyph lists draw.
updated_at?: string | null
created_at?: string | null
approvalElsewhere?: boolean // Someone else approves this work: its approval steps are not the reader's to act on.
tasks?: Array<{
id: string
title: string
status: string | null
task_type?: string | null
module_type?: string | null
step_kind?: string | null
artifact_type?: string | null
completion_mode?: string | null
due_date?: string | null
max_days?: number | null
created_at?: string | null
post?: {
chip: string // Where the step's post is, as the Posts list says it: draft, in_review, approved_unscheduled, scheduled, sending, manual_pending, attention, published, deleted, cancelled or unconnected.
scheduledAt: string | null // The next time one of its destinations goes out (ISO), when one is scheduled.
}
| null // Only on the single «Publicación» step of a «Post» work whose draft exists.
}>
}>
activeTotal: integer // -9007199254740991–9007199254740991
pinnedIds: string[]
pinnedOrder: string[]
workOrder: string[]
fetchedAt: number
today: string
timeZone?: string | null
}One page of the brand's «Works» exactly as the app draws it: each work with its step counts (total, done, in progress), up to three open steps waiting for the brand (approval steps only where the reader is the approver) and its product name. Active by default; archived for the archive. Pages by offset/limit (max 72). For a compact, searchable list use works.list.
| Field | Value |
|---|---|
| Kind | Read |
| HTTP method | POST /api/v1/works.screen.list |
| MCP tool | works_screen_list |
| Scope | works.read |
| Minimum role | Viewer |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
archived?: boolean
offset?: integer // 0–100000
limit?: integer // 1–72
}Output
{
works: Array<{
id: string // uuid
name: string
status: string
due_date: string | null
is_recurring: boolean | null
recurring_interval: string | null
archived_at: string | null
created_at: string
updated_at: string
source_product_id?: string | null
product_name?: string | null
product_icon?: string | null
task_count: number // Steps in scope: not informational, not canceled.
completed_count: number
working_count: number // Steps Nömad is working on right now.
client_pending_count: number // Open steps waiting for the brand.
}>
total: integer // -9007199254740991–9007199254740991
nextOffset: integer // -9007199254740991–9007199254740991
hasMore: boolean
error: string | null
}One work exactly as its page draws it: the work row, the first page of its steps (with who at Nömad holds each), who approves it, the approved deliverables, the subscription a recurring work comes from and its product name. not_found when it is not this brand's. For the compact shape use works.get.
| Field | Value |
|---|---|
| Kind | Read |
| HTTP method | POST /api/v1/works.screen.work |
| MCP tool | works_screen_work |
| Scope | works.read |
| Minimum role | Viewer |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
workId: string // uuid
preview?: boolean // Staff previewing the brand as a client: edit controls are left out.
}Output
{
work: {
id: string // uuid
brand_id: string // uuid
name: string
status: string
color: string | null
due_date: string | null
source: string | null
source_product_id: string | null
is_recurring: boolean | null
recurring_interval: string | null
archived_at: string | null
archived_by: string | null
created_at: string
updated_at: string
}
tasks: {
tasks: Array<{
id: string // uuid
work_id: string // uuid
title: string
description: string | null
status: string
task_type: string | null
completion_mode: string | null
module_type: string | null
position: number | null
due_date: string | null
client_answers: unknown // Answers by question id.
client_submitted_at: string | null
output_url: string | null
template_id: string | null
updated_at: string
}>
total: integer // -9007199254740991–9007199254740991
nextOffset: integer // -9007199254740991–9007199254740991
hasMore: boolean
error: "loadFailed" | null
}
approvers: Record<string, unknown> | null
operationalDeliverables: Array<{
id: string
taskId: string
taskTitle: string
title: string
revision: integer // -9007199254740991–9007199254740991
}>
subscription: {
id: string
name: string
}
| null
productName: string | null
}One page of a work's steps exactly as its page draws them, in order, with who at Nömad holds each. Pages by offset/limit (max 500).
| Field | Value |
|---|---|
| Kind | Read |
| HTTP method | POST /api/v1/works.screen.tasks |
| MCP tool | works_screen_tasks |
| Scope | works.read |
| Minimum role | Viewer |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
workId: string // uuid
offset?: integer // 0–100000
limit?: integer // 1–500
}Output
{
work: {
id: string // uuid
brand_id: string // uuid
name: string
status: string
color: string | null
due_date: string | null
source: string | null
source_product_id: string | null
is_recurring: boolean | null
recurring_interval: string | null
archived_at: string | null
archived_by: string | null
created_at: string
updated_at: string
}
| null
tasks: {
tasks: Array<{
id: string // uuid
work_id: string // uuid
title: string
description: string | null
status: string
task_type: string | null
completion_mode: string | null
module_type: string | null
position: number | null
due_date: string | null
client_answers: unknown // Answers by question id.
client_submitted_at: string | null
output_url: string | null
template_id: string | null
updated_at: string
}>
total: integer // -9007199254740991–9007199254740991
nextOffset: integer // -9007199254740991–9007199254740991
hasMore: boolean
error: "loadFailed" | null
}
}One task exactly as its page draws it: the task, its work, the sibling steps, who approves, and what its module asks for (questionnaire, change rounds with signed files, Nödo briefing, editorial board, domain choice, payment). A «Publicación» task answers kind: "publication" with the common part only; its post is read with the publishing operations. not_found when it is not this brand's.
| Field | Value |
|---|---|
| Kind | Read |
| HTTP method | POST /api/v1/works.screen.task |
| MCP tool | works_screen_task |
| Scope | works.read |
| Minimum role | Viewer |
| Human confirmation | No |
| Doors | API, MCP, Screens, Apps, Nödo |
| Status | Available |
Input
{
workId: string // uuid
taskId: string // uuid
preview?: boolean // Staff previewing the brand as a client: edit controls are left out.
fallbackPillars?: string[] // ≤ 6 items · Pillars an editorial plan previews when the briefing has none (in the reader's language).
}Output
{
kind: "task" | "publication"
work: {
id: string // uuid
brand_id: string // uuid
name: string
status: string
color: string | null
due_date: string | null
source: string | null
source_product_id: string | null
is_recurring: boolean | null
recurring_interval: string | null
archived_at: string | null
archived_by: string | null
created_at: string
updated_at: string
}
task: {
id: string // uuid
work_id: string // uuid
title: string
description: string | null
status: string
task_type: string | null
completion_mode: string | null
module_type: string | null
position: number | null
due_date: string | null
client_answers: unknown // Answers by question id.
client_submitted_at: string | null
output_url: string | null
template_id: string | null
updated_at: string
step_kind: string | null
artifact_type: string | null
accept_text: boolean | null
accept_files: boolean | null
accept_questionnaire: boolean | null
is_required: boolean | null
estimated_hours: number | null
estimated_minutes: number | null
max_days: number | null
depends_on: string[] | null
client_text: string | null
client_files: unknown // URLs of the files the brand attached.
output_text: string | null
created_at: string
}
siblings: Array<{
id: string // uuid
title: string
}>
approvers: Record<string, unknown> | null
questions?: Array<{
id: string
question: string
sort_order?: number | null
field_type?: string | null
placeholder?: string | null
is_required?: boolean | null
options?: unknown // The choices (a list) or the field's settings: `choices`, `allow_other`, lengths and file limits.
helper_text?: string | null
}>
}What a deleted work or step shows when its link is opened, instead of a 404: its name, when it was deleted, who did it and whether the caller may restore it (an own step within its undo window; a work is restored by Nömad). deleted is null when the record is live, foreign or never existed; the live reads (works.screen.work, works.screen.task) keep answering not_found for it.
| Field | Value |
|---|---|
| Kind | Read |
| HTTP method | POST /api/v1/works.screen.deleted |
| MCP tool | works_screen_deleted |
| Scope | works.read |
| Minimum role | Viewer |
| Human confirmation | No |
| Doors | Screens, Apps, API |
| Status | Available |
Input
{
workId: string // uuid
taskId?: string // uuid
}Output
{
deleted: {
entity: "work" | "task"
id: string // uuid
workId: string // uuid
name: string
deletedAt: string
deletedBy: {
id: string // uuid
name: string | null
}
| null
restorable: boolean
}
| null
}Updated on January 1, 1970