Skip to content

Tools Reference

Every tool that acts on the outside world on your behalf works in two calls: inboxSendTool, commentActTool (reply, delete), automationManageTool (pose, updatePose, removePose, replay, delete), webhookManageTool (create, delete), postDeleteTool, contentDeleteTool and postUpdateTool (status: schedule).

  1. The first call (without confirmationToken) does nothing. It returns needsConfirmation: true, a preview of exactly what would happen, and a confirmationToken.
  2. Show the user the preview and get an explicit yes.
  3. The second call, with the same parameters and the token, acts.

The token is bound to your workspace, the action and its exact parameters (another text, URL or comment is refused), it works once, and it expires after 15 minutes. Anything else needs a new first call.


List all connected social media accounts (channels) for your organization.

Parameters:

Field Type Required Description
group string No Group (customer) ID from groupList. When provided, only channels belonging to that group are returned

Returns:

Field Type Description
id string Integration ID (use this when scheduling posts)
name string Display name of the account
picture string Profile picture URL
platform string Platform identifier: instagram-standalone, tiktok or youtube
customer object The group (customer) this channel belongs to, as { id, name }, omitted if the channel is not assigned to a group

List all groups (customers) for your organization. Use a group’s id with integrationList to filter channels down to a single group.

Parameters: None

Returns:

Field Type Description
id string Group (customer) ID (pass to integrationList as group)
name string Group (customer) display name

Get the posting rules, character limits, required settings, and available helper tools for a specific platform. Call this before scheduling a post to understand what the platform expects.

Parameters:

Field Type Required Description
isPremium boolean Yes Whether the user has a premium subscription
platform string Yes Platform identifier: instagram-standalone, tiktok or youtube (the tool accepts every identifier of the original project, but these are the channels UseNadia connects)

Returns:

Field Type Description
rules string Platform-specific posting rules and best practices
maxLength number Maximum character length for posts
settings object JSON schema of required settings for this platform
tools array Platform-specific helper tools (see triggerTool)

The tools array contains helper functions specific to the platform, called through triggerTool.

Each tool in the array has:

Field Type Description
methodName string Function name to pass to triggerTool
description string What the tool does
dataSchema array Parameters the tool accepts

Execute a platform-specific helper function. These are discovered through integrationSchema (its tools array) and fetch dynamic data a setting needs before a post can be scheduled.

Parameters:

Field Type Required Description
integrationId string Yes The integration ID from integrationList
methodName string Yes The function name from integrationSchema tools
dataSchema array Yes Key-value pairs of parameters for the function

Each item in dataSchema:

Field Type Description
key string Parameter name
value string Parameter value

Returns: whatever the helper returns, usually a list of { label, value } options to put in a setting.


Schedule, draft, or immediately publish posts to social media platforms. This is the main tool for creating content.

Parameters:

Field Type Required Description
socialPost array Yes Array of posts to create

Each item in socialPost:

Field Type Required Description
integrationId string Yes Integration ID from integrationList
contentId string No The board card the post is made from, from contentListTool. Links the post to the card: the card moves to PUBLISHED by itself when the post goes live
isPremium boolean Yes Whether the user has premium
date string Yes UTC datetime (e.g., 2025-01-15T10:00:00.000Z)
shortLink boolean Yes Whether to shorten links in the post
type string Yes draft, schedule, or now
postsAndComments array Yes The post content and optional comments
settings array Yes Platform-specific settings from integrationSchema

Each item in postsAndComments:

Field Type Description
content string The text of the post, plain (see formatting below)
attachments array Array of image/media URLs

Each item in settings:

Field Type Description
key string Setting name
value any Setting value (prefer IDs over labels when available)

Send the text as a person would type it: plain text, one line per sentence, an empty line between paragraphs. No HTML, no <p>, no <br>. Nadia formats it for each platform and keeps your line breaks: an empty line in your text is an empty line in the published caption, on Instagram as on TikTok.

Freelance en mission longue = CDI déguisé ? Non, et voilà pourquoi.
On me le dit souvent : « t'es pas un vrai entrepreneur ».
Abonne-toi à @vincentleserpent pour apprendre à coder.
#freelance #developpeur #cdi

HTML is still accepted, for clients that already send it (the dashboard, the public API): a content that carries a tag is stored as it is, with these tags only.

Tag Usage
<p> One line; an empty <p></p> is an empty line
<h1>, <h2>, <h3> Headings
<strong> Bold text
<u> Underlined text
<ul>, <li> Lists

The first item of postsAndComments is the post. On the channels UseNadia connects:

  • instagram-standalone: the following items are posted as comments under the publication, text only — an Instagram comment cannot carry media;
  • tiktok: extra items are ignored, only the first one is published;
  • youtube: extra items are ignored too.

To schedule multiple posts (e.g., 20 posts across different days), add multiple items to the socialPost array, each with its own date and integrationId.

Returns:

Field Type Description
postId string The created post ID
integration string The integration it was posted to

If validation fails, returns { errors: string } with details about what went wrong (e.g., content exceeds character limit).


Read the calendar: the organization’s posts (drafts, scheduled and already published) between two dates, or a single post in full. Read-only.

Parameters:

Field Type Required Description
postId string No Only this post, in full, with its thread. The dates are then ignored
startDate string Without postId UTC date for the start of the range (e.g. 2026-07-20T00:00:00Z)
endDate string Without postId UTC date for the end of the range (e.g. 2026-07-27T00:00:00Z)
integrationId string No Only the posts of this channel, from integrationList

Returns:

An object with a posts array. Each item has:

Field Type Description
id string Post ID
group string The post group ID (shared across a post and its per-channel variations)
state string Post state (QUEUE, DRAFT, PUBLISHED, or ERROR)
publishDate string UTC datetime of the post (YYYY-MM-DD HH:mm)
content string The post text, without HTML. Over a date range, an excerpt of 280 characters; with postId, in full
integrationId string ID of the channel
channel string Display name of the channel
platform string Platform identifier (e.g. instagram-standalone, tiktok)
thread string[] With postId only: the comments posted under it, in order
releaseId string With postId only: the platform’s ID of the publication once published (the media ID of the Instagram tools), or missing when its media never reached the platform
releaseURL string With postId only: the publication’s URL
missingMedia array With postId only, when releaseId is missing: the files that never reached the platform (id, url)

Change what a post is without rewriting it: take a scheduled post out of the queue, put a draft back in it, or record the platform’s own ID of a post published outside UseNadia.

Parameters:

Field Type Required Description
postId string Yes The post, from postsListTool
status string No draft (out of the queue) or schedule (back in the queue at its date)
releaseId string No The platform’s ID of the publication (Instagram media ID, TikTok video ID…), so analytics, comments and automations find it
confirmationToken string status: schedule, second call The token of the first call, once the user said yes

Putting a draft back in the queue (status: schedule) makes it go out at its date, so it is a confirmed action. Taking a post out of the queue and recording a releaseId are not.

Returns: { updated, needsConfirmation?, preview?, confirmationToken?, errors? }.


Delete a post and everything scheduled with it (its per-channel variations and its thread). A scheduled post is cancelled; a published one is removed from UseNadia, not from the platform. Irreversible, so it is a confirmed action: the preview names the post’s date, channel and first words.

Parameters:

Field Type Required Description
postId string One of the two The post, from postsListTool
group string One of the two The group of the post, from postsListTool
confirmationToken string Second call The token of the first call, once the user said yes

Returns: { deleted, group, needsConfirmation?, preview?, confirmationToken?, errors? }.


The next free slot in a channel’s posting schedule (the time slots set on the channel, skipping those already taken). Read-only.

Parameters:

Field Type Required Description
integrationId string No The channel. Without it, the next free slot across the workspace

Returns: { date } — UTC, ISO 8601, ready for integrationSchedulePostTool.


List the comment → DM automations of the workspace (Instagram): the ids the Instagram settings of a post ask for, and what already runs on a publication. Read-only.

A post names its automation by an id in its Instagram settings: automationFlowId (a template drawn in the app), with automationKeywords and automationVariables. Words or values sent without the id are refused at scheduling, because nothing would run.

Parameters:

Field Type Required Description
flowId string No Only this template, with every publication it is posed on
integrationId string No An Instagram channel, from integrationList. Also returns what runs on its publications
postId string No With integrationId: only what runs on this publication. A post ID from postsListTool, or an Instagram media ID

Returns:

Field Type Description
templates array The automations drawn in the app: id (pass as automationFlowId), name, status (only ACTIVE ones run), ready, issues, trigger (post_comment or story_reply), keywordsRequired, variables (the names to fill in automationVariables), poses
poses array With integrationId: the templates running on the channel’s publications; with flowId alone: every publication that template is posed on. Each with id (the poseId of automationManageTool and automationRunsTool), flowId, flowName, postId, mediaId, keywords, variables, active, runs

To put on a new post the automation of an earlier one, read that post’s pose with integrationId and postId, then schedule with the same automationFlowId and automationKeywords and only the values of automationVariables that change.


Everything the public API does to a template or a pose, short of drawing the tree of steps (that is the editor in the app). One action per call.

Parameters:

Field Type Required Description
action string Yes pose, updatePose, removePose, poll, replay, activate, pause, delete, rename, createFromPreset
flowId string Per action The template (pose, activate, pause, delete, rename)
poseId string Per action The pose, from automationList (updatePose, removePose, poll, replay)
integrationId string pose The Instagram channel (also rename, createFromPreset)
mediaId string pose The publication already live, from commentsListTool
kind string No post or story (default: the template’s trigger)
keywords string[] pose, updatePose The trigger words of this publication
variables object pose, updatePose One value per variable of the template
active boolean updatePose false pauses the pose
commentIds string[] replay 1 to 50 comment IDs, from commentsListTool
resend boolean No replay: restart a comment that already has a run
name string No rename, createFromPreset
preset string createFromPreset lead_magnet, newsletter, link, qualify or blank
language string No createFromPreset: fr (default) or en
confirmationToken string Second call pose, updatePose, removePose, replay, delete: the token of the first call

Returns: { ok, errors? } plus pose, template, poll (checked, started) or replay (one outcome per comment) depending on the action. A pose posed on a post you schedule does not go through here: pass automationFlowId, automationKeywords and automationVariables in the post’s Instagram settings.

pose, updatePose, removePose, replay and delete are confirmed actions: they make the account write to people, or cannot be undone. poll, activate, pause, rename and createFromPreset act at once. activate is refused while the template has errors.


The people who went through a pose: one row per person, newest first. Read-only.

Parameters:

Field Type Required Description
poseId string Yes The pose, from automationList
status string No PENDING, WAITING, DELAYED, DONE, HANDED_OFF, FAILED or SKIPPED

Returns: { runs, total }. Each run: id, username, keyword, text (the comment or message that started it), status, email, tags, isFollower, error (Meta’s message on a failure), startedAt, completedAt.


The Instagram side of a channel, live from Meta: recent publications, the stories live right now, or the comments under one publication. Read-only.

Parameters:

Field Type Required Description
integrationId string Yes The Instagram channel
kind string Yes publications, stories or comments
mediaId string comments The publication: an Instagram media ID, or the releaseId of a post read with postsListTool

Returns: publications (id — the media ID a pose watches —, type, caption, permalink, publishedAt, comments, likes) or comments (id, from as @username, text, at, replyTo, hidden), oldest first.


Reply publicly to a comment, hide or unhide it, or delete it on Instagram.

Parameters:

Field Type Required Description
integrationId string Yes The Instagram channel
commentId string Yes The comment, from commentsListTool
action string Yes reply, hide, unhide or delete
message string reply The public answer, 2,200 characters max
confirmationToken string reply, delete The token of the first call, once the user said yes

A reply is seen by everyone at once and a deletion is for good, so both are confirmed actions: the token is bound to this exact comment and text, single use, 15 minutes. Hiding is reversible and needs no confirmation.

Returns: { done, needsConfirmation?, preview?, confirmationToken?, errors? }.


The direct message inbox (DMs) of an Instagram channel: the conversations, most recent first, each with the person, the date, its status in the inbox (NEEDS_REPLY = a human is waiting for an answer, AUTOMATED = an automation handled it) and its last message. Read-only.

Attachments are flattened: a card sent by an automation (ManyChat, UseNadia’s own flows) comes back as its text with its buttons and their links, a shared Reel or post as its permalink.

Parameters:

Field Type Required Description
integrationId string Yes The Instagram channel, from integrationList
username string No Only the conversation with this person (@username or their ID). The search reads the 200 most recent conversations
limit integer No How many conversations, 1 to 100. 25 by default

Returns:

Field Type Description
channel string Display name of the channel
conversations array Each with id (pass to inboxReadTool), with (@username of the person), recipientId, participants, updatedAt, status, replyWindowOpen (whether Instagram still accepts an answer: only within 24 h of the person’s last message) and lastMessage
errors string Why nothing came back (a channel that is not in the workspace, Meta’s error)

Each message, here and in inboxReadTool: at, from (@username of the sender), text, attachments (kind — template, reel, share, story_reply, story_mention, image, video… — with text, url, storyId, buttons) and unsupported when the API does not show the message type (a voice note, a GIF).

Example: who is waiting for an answer.

{ "integrationId": "abc123", "limit": 50 }

One direct message conversation in full: its last 50 messages, oldest first. Get the conversation ID with inboxListTool first. Read-only.

Parameters:

Field Type Required Description
integrationId string Yes The Instagram channel
conversationId string Yes The conversation, from inboxListTool

Returns: channel and conversation: id, with, recipientId, updatedAt, replyWindowOpen, replyWindowClosesAt (when Instagram stops accepting an answer, 24 h after the person’s last message; after that only they can reopen the conversation by writing again) and messages, in the shape described under inboxListTool. Or errors.

Example:

{ "integrationId": "abc123", "conversationId": "t_1234567890" }

Send a direct message (DM) on an Instagram channel, in an existing conversation: Instagram only lets an account write to someone who wrote first.

A DM is seen by the person immediately and cannot be taken back, so it is a confirmed action. The first call sends nothing and returns a preview and a confirmationToken, signed over the exact channel, recipient and text, single use, valid 15 minutes. Once the user has said yes to that exact recipient and text, the second call with the same parameters and the token sends it. Changing the text needs a new first call.

Parameters:

Field Type Required Description
integrationId string Yes The Instagram channel
conversationId string One of the two The conversation, from inboxListTool
recipient string One of the two @username or ID of the person, when no conversationId
text string Yes The message, plain text, 1 to 1,000 characters
linkUrl string No A link, sent as a button under the text
linkButtonText string No Label of that button, 20 characters max
confirmationToken string Second call The token of the preview, only once the user said yes to that exact message

Returns: { sent, needsConfirmation?, preview?, confirmationToken?, messageId?, errors? }. The preview holds channel, integrationId, conversationId, to, recipientId, text, linkUrl, linkButtonText and replyWindowClosesAt.

When the 24 h window is known to be closed, the first call already refuses with errors and nothing is proposed: only the person can reopen the conversation. Do not retry.

Example: first call, then the same with the token.

{ "integrationId": "abc123", "recipient": "@someone", "text": "Here is the guide", "linkUrl": "https://example.com/guide", "linkButtonText": "The guide" }

Read the inbox of an Instagram channel now, for what Meta’s webhook missed: new direct messages and story replies are picked up, and the automations waiting on them move on. Nothing re-reads the inbox on a schedule, so this is the catch-up. Nothing is sent.

Parameters: integrationId (string, required).

Returns: { polled, channel, conversations, handled, errors? }: conversations read from Meta, handled the inbound messages that reached a waiting automation.


Generate an AI image to use as a post attachment.

Parameters:

Field Type Required Description
prompt string Yes Description of the image to generate

Returns:

Field Type Description
id string Media ID
path string URL of the generated image

Use the returned path in the attachments array when scheduling a post.


List all available video generation types and their required parameters.

Parameters:

Field Type Required Description
reasoning string No A short note on why the options are being listed. Ignored by the server, it only helps the agent’s trace

Returns: { video }, an array of video generators, each with:

Field Type Description
type string Video type identifier (e.g., image-text-slides, veo3)
output string Supported orientations: vertical|horizontal
tools array Helper functions (call with videoFunctionTool)
customParams object JSON schema of required parameters
Type Description Requirements
Image Text Slides Slide-based videos with text-to-speech prompt, voice (get voice ID via videoFunctionTool)
Veo3 AI-generated video with audio prompt, optional images (max 3)

Execute helper functions for video generators. Use this to fetch required data before generating a video (e.g., listing available voices).

Parameters:

Field Type Required Description
identifier string Yes Video type identifier from generateVideoOptions
functionName string Yes Function name from the video type’s tools array

Example: Call with identifier: "image-text-slides" and functionName: "loadVoices" to get available ElevenLabs voice IDs.


Generate a video to use as a post attachment.

Parameters:

Field Type Required Description
identifier string Yes Video type from generateVideoOptions
output string Yes vertical or horizontal
customParams array Yes Key-value pairs of parameters for the video type

Each item in customParams:

Field Type Description
key string Parameter name
value any Parameter value

Returns:

Field Type Description
url string URL of the generated video

Use the returned url in the attachments array when scheduling a post.


Move an existing post to another date and time (UTC). Get the post ID from postsListTool first.

Moving is reversible — move it back — so unlike scheduling it does not go through a confirmation. A post that has already been published cannot be moved.

Parameters:

Field Type Required Description
postId string Yes The post to move
date string Yes The new date, UTC (YYYY-MM-DD HH:mm:ss)

Returns:

Field Type Description
moved boolean Whether the post was moved
postId string The post ID
date string Its new date
errors string Why it was not moved

Read how the videos of a TikTok or Instagram channel perform, from the history UseNadia collects every 30 minutes. This tool has no equivalent in the original project, and it is the one that makes “how is my last video doing” answerable.

It is read-only and calls no provider: everything comes from the collected series. A channel with collection switched off answers collected: false with the reason.

Parameters:

Field Type Required Description
integrationId string Yes The channel whose videos to read
videoId string No The provider video ID to focus on. Defaults to the newest
limit number No How many of the newest videos to read, 1 to 30. Defaults to 10

Returns, per video: the current counters (views, reach, likes, comments, shares, saves, watch time), the engagement rates as a percentage of views, the current skip rate (skipRatePercent, Instagram Reels only, lower is better), the views reached at fixed ages (H+4, H+12, H+24, H+48, H+72, H+120, H+168) and the views gained over the last 24 and 48 hours.

The focus video is additionally compared with the others at its own age — rank and median — with a projection to H+120 from the channel’s own H+24 → H+120 multiplier, its current velocity, and the follower count with its 24 and 48 hour gain.


The metrics of a channel over the last days, read live from the platform (cached one hour): followers, reach, impressions, views, likes… whatever the platform gives. With postId, the metrics of that one published post. Read-only.

Parameters:

Field Type Required Description
integrationId string Yes The channel
days integer No The window in days (default 30)
postId string No One published post of this channel instead of the account
series boolean No true adds the day-by-day points of each metric

Returns: { metrics }. Each metric: label, latest (the last value), total (the sum over the window), percentageChange against the previous window, and series when asked. With postId, missing: true says the post’s media never reached the platform.


The raw history UseNadia collects every 30 minutes on a TikTok or Instagram channel, as time series: the account’s counters, or each video’s. For a ready-made reading, videoPerformance comes first; this one is for a chart, an export, or a question it does not answer. Read-only.

Parameters:

Field Type Required Description
integrationId string Yes The channel
kind string Yes account or video
videoId string No video: only this video (the platform’s ID)
from, to string No ISO 8601. Default: the last 30 days
limit, offset integer No Pagination

Returns: { items, total, from, to }, plus videos (title, cover, duration of the IDs present) and hidden on the video series — the same shape as the history endpoints of the Public API.


Read the content board: one card per video, in columns IDEA → SCRIPT → VALIDATED → TO_SHOOT → TO_EDIT → TO_SCHEDULE → PUBLISHED. Read-only. This tool has no equivalent in the original project.

Parameters:

Field Type Required Description
contentId string No Only this card
stage string No Only the cards of this column
withNumbers boolean No Add the numbers of the published cards (slower)

Returns a contents array. Each card has id, externalId (your own ID when the card was created with one, otherwise null), title, stage, tags, hook, hookText (the text shown on screen over the first seconds), script and notes (in full), resourceStatus, resourceUrl, resourceBrief, integrationIds, plannedAt, hasVideo, scheduledPosts (channels of the post scheduled from it), publishedAt and, with withNumbers, numbers: views, engagementRate, followersGained, leads, emails.


Add a card to the board. It lands at the bottom of its column. A card is visible and reversible on the board, so this tool writes directly, with no confirmation.

Parameters:

Field Type Required Description
title string Yes Short title of the video
stage string No The column to start in. Default IDEA
hook string No The spoken hook, the first seconds
hookText string No The text shown on screen over the first seconds
script string No
notes string No
tags string[] No Free labels, e.g. a series
resourceStatus string No The resource the video gives away: READY, or TO_CREATE (the card then stays out of TO_SCHEDULE and PUBLISHED)
resourceUrl string No Where the resource lives, or will live
resourceBrief string No What the resource holds, or the prompt to make it
integrationIds string[] No Target channels, from integrationList
plannedAt string No Planned publication date, UTC (YYYY-MM-DD HH:mm:ss)
externalId string No Your own ID for the card (an import, a pipeline). With it the call is an upsert: the card holding this ID is updated with the fields sent instead of a second one being created

Returns created (or updated on an upsert), the card’s id and stage, or errors.


Edit a card and/or move it to another column, in one call. Only the fields given change. Get the card ID from contentListTool first.

Parameters: contentId (required), then any of stage (moves the card to the bottom of that column), title, hook, hookText, script, notes, tags (replaces the list), resourceStatus, resourceUrl, resourceBrief, integrationIds (replaces the list), plannedAt, postGroup (ties the card to a post already in the calendar: the group of that post, from postsListTool; each call adds one, and the card moves to PUBLISHED by itself when the first of its posts goes live).

Returns updated, the card’s id and stage, or errors when the card does not exist in the workspace, or when its resource is still TO_CREATE and the move goes to TO_SCHEDULE or PUBLISHED (the fields are written, the card stays where it is).


Delete a card of the board. The posts scheduled from it stay in the calendar. It cannot be undone from the app, so it is a confirmed action: the preview names the card.

Parameters:

Field Type Required Description
contentId string Yes The card to delete
confirmationToken string Second call The token of the first call, once the user said yes

Returns { deleted, needsConfirmation?, preview?, confirmationToken?, errors? }; errors when the card does not exist in the workspace.


The tool to call when someone wants hooks for a video. Returns a catalogue of hook forms (families) for the video being prepared, each with real hooks from the library — one on the subject itself when the library has one, the others drawn at random among the hooks of the family. Two calls never give the same examples. Read-only.

The forms are ordered by their measured effect on that nature of video, but the order is weak. Views never certify a hook: they follow the size of the subject, so normViews is information, not a ranking. The method: say what the video delivers and its subject, write one candidate per form by adapting the form of the example (never its subject), let the person pick. Never invent a hook from scratch, never copy one verbatim, never name a creator.

Parameters:

Field Type Required Description
nature string No What the video delivers: tuto_methode, ressource_outil, liste_conseils, explication_concept, actu, opinion, story_perso, story_tiers, demo_build, humour_sketch, vie_coulisses. Omitted: the whole corpus
q string No Words of the subject (accents and case ignored)
language string No fr (default), en or all
forms integer No How many forms, 1 to 15. Default 7
examples integer No Real hooks per form, 1 to 5. Default 2

Returns: { forms }. Each form: family, label, measuredOn (the nature the numbers come from, all = the whole corpus), ratio (views vs the rest at equal baseline), bangers (share of videos at twice the baseline or more), accountsFor, accountsAgainst, verdict and examples — each with hook (the first sentence), opening (the first ~40 words, context only), normViews (5 = five times what that account usually does), year, nature, subject and onSubject (whether this hook is about the subject asked).

Example:

{ "nature": "liste_conseils", "q": "malte expatriation", "forms": 5 }

Search the library of real hooks that worked: about 26,000 first sentences of videos, each with its views at the baseline of its account. For “give me hooks for my video”, hooksFormsTool comes first; this one is the search by words, family or nature. Read-only. Experimental, like hooksFormsTool.

Parameters:

Field Type Required Description
q string No Words of the subject, any of them. Hooks matching the most words come first
family string No Only this hook family (slug): promesse_directe, ciblage_si_tu, ressource_cadeau, interdiction_erreur, reset_fantasy, story_perso, story_tiers, verite_cachee, peur_menace, avant_apres, defi_demo, opinion_polemique, actu_nouveaute, comparatif_meilleur, obligation_urgence, chiffre_fait_choc, question…
nature string No Only videos of this nature (same values as hooksFormsTool)
language string No fr (default), en or all
minNorm number No Floor on normalised views. Default 2 (at least twice the baseline of its account); lower it to 1.5 when the subject is rare
limit integer No 1 to 100. Default 15
withFamilies boolean No Also return the measured effect of each hook family

Returns: total (the size of the whole library) and hooks, each with year, language, hook, opening, views, normViews, family, nature, concrete, subject, lockinGestures and matchedWords. With withFamilies, families: family, n, accounts, ratio, bangers, accountsFor, accountsAgainst, verdict — only a family whose verdict is proven is a rule, the others are chosen for fit.

Example:

{ "q": "impôts malte", "minNorm": 1.5, "withFamilies": true }

Royalty-free music for a video: public domain and CC-BY tracks only, each file prepared (dynamics flattened, normalised to a known loudness) and downloadable at its url. Use it when a video needs a bed under the voice. Read-only. Experimental, like the hooks tools.

Pillars: piano (storytelling, educational — the default when in doubt), news (tension, reveal), synthwave (tech, tools, AI), epique (cinematic, big announcement). Give durationS so that tracks at least as long come first: a shorter track loops, with an audible seam on a crescendo. When creditLine is not null, it goes at the bottom of the description, before the hashtags — the licence depends on it.

Parameters:

Field Type Required Description
pillar string No piano, news, synthwave or epique. Omitted: the whole catalogue
durationS number No Length of the video in seconds: tracks at least this long come first
q string No Words of a title or an artist
moreChoice boolean No Also return the limite tracks (a bit fast, or a punch early on: usable, less safe under a voice)
limit integer No 1 to 100. Default 10

Returns: total (tracks in the whole catalogue), howTo (level, mix and credit: the same recipe for every track) and tracks, each with slug, title, artist, pillar, durationS, bpm, intro, verdict (ok or limite), verdictWhy, license, creditLine (paste as is, or null), url (the prepared mp3) and storedLufs (integrated loudness of the file).

Example:

{ "pillar": "piano", "durationS": 95 }

Import an image or video into the media library from a URL. The server downloads the file itself: the bytes never go through the MCP call or the assistant.

Use it before scheduling a post when the media lives somewhere else: an attachment that is not already hosted on UseNadia’s own domain fails upload-domain validation. The URL must be HTTPS and only has to be reachable from the server without a login — a public URL, or a signed URL that expires (R2, S3, a video another tool handed over with its download link). Private, loopback and link-local addresses are refused, after each redirect too.

The file goes through the same checks as a confirmed direct upload (real type sniffed from the bytes, ffprobe) and comes back with its numbers, so the caller can compare them with what the source said: a different size means the download is not the file that was meant.

Parameters:

Field Type Required Description
url string Yes The HTTPS URL of the image or video, reachable without a login

Returns:

Field Type Description
id string Media ID
path string Hosted URL — use this in the attachments array
contentType string video/mp4, image/jpeg, image/png, image/webp or image/gif — the type read from the bytes
size number Bytes stored
duration number | null Seconds for a video, null for an image
width, height number Displayed dimensions, rotation applied
codec string Picture codec (h264, hevc, png…)

Accepted types and size limit are those of createUploadUrl (500 MB by default). Errors carry a code: URL_UNREACHABLE (not public, expired, or answered an error), FILE_TOO_LARGE, UNSUPPORTED_CONTENT_TYPE, FILE_CORRUPTED, DOWNLOAD_INTERRUPTED.


Get a one-time URL to upload a file that sits on the client’s own disk — a video cut and compressed in an AI assistant’s code sandbox, for example — when there is no public URL to give uploadFromUrlTool. The bytes never go through the MCP call: the client PUTs them with curl, then calls confirmUpload.

The sequence: createUploadUrl → run the returned curl command → confirmUpload → integrationSchedulePostTool (or splitVideoIntoStories).

Every upload URL lives on the app’s own host (https://app.usenadia.com/api/uploads/…): it is the only host a sandbox’s network allow-list needs. It is valid 15 minutes, for one file, of the declared type and size, in the organization that asked for it, and gives access to nothing else.

Parameters:

Field Type Required Description
filename string Yes Name or path of the file on the client’s disk, reused in the curl command; its base name becomes the media name
contentType string Yes video/mp4, image/jpeg, image/png, image/webp or image/gif
size number Yes Exact size in bytes. 500 MB maximum by default (NADIA_DIRECT_UPLOAD_MAX_BYTES)

Returns:

Field Type Description
uploadId string To pass to confirmUpload
uploadUrl string Where to PUT the file
method string Always PUT
headers object The exact headers to send: Content-Type and Content-Length
expiresAt string ISO date, 15 minutes after the call
maxSize number The size limit of this server, in bytes
curl string The command to run as is, e.g. curl --fail-with-body -X PUT -T 'reel.mp4' -H 'Content-Type: video/mp4' 'https://app.usenadia.com/api/uploads/…'

The PUT answers 201 with { uploadId, size }, or an error whose message starts with a code: UPLOAD_URL_EXPIRED (410), UPLOAD_URL_ALREADY_USED (409), CONTENT_TYPE_MISMATCH (415), SIZE_MISMATCH (400), FILE_TOO_LARGE / SIZE_EXCEEDED (413), UPLOAD_URL_INVALID (404). A transfer that fails halfway does not use the URL up: run the same command again.


Finish an upload once its PUT answered 201. Checks the size, that the bytes are the declared type, and for a video that ffprobe can read it (codec, duration, dimensions as displayed — the rotation of a phone video is applied). Then adds the file to the media library. Calling it again returns the same media.

Parameters:

Field Type Required Description
uploadId string Yes From createUploadUrl

Returns:

Field Type Description
id string Media ID
path string Hosted URL — use it in attachments, or as videoUrl in splitVideoIntoStories
contentType string The declared type, checked
size number Bytes
duration number | null Seconds, null for an image
width / height number As displayed
codec string e.g. h264

Errors: FILE_NOT_UPLOADED, UPLOAD_IN_PROGRESS, UPLOAD_URL_EXPIRED, FILE_TYPE_MISMATCH, FILE_CORRUPTED, SIZE_MISMATCH, UPLOAD_NOT_FOUND. Uploads never confirmed are deleted after 24 hours.


List the media library, newest first. Read only, limited to your workspace. This is how an agent finds the video you just uploaded from your phone without asking you for a link.

Parameters:

Field Type Required Description
type string No video or image; both when omitted
search string No Part of the file name, case insensitive
since string No Only media uploaded at or after this UTC date (ISO 8601)
limit number No 20 by default, 100 at most
cursor string No nextCursor of the previous call, for the next page

Returns media and nextCursor (null on the last page). Each media:

Field Type Description
id string Media ID
path string Hosted URL: an attachments entry of integrationSchedulePostTool, the input of transcribe, cutVideo and splitVideoIntoStories
filename string Original file name
type string video or image
size number Bytes, null if unknown
createdAt string Upload date, ISO 8601 UTC
duration number Videos only: seconds
width, height number Videos only: displayed size, rotation applied (height > width is vertical)

Size, length and dimensions are read with ffprobe the first time a media is listed, then kept.


Transcribe a video of the library with ElevenLabs Scribe (language detected automatically), with timestamps.

Parameters:

Field Type Required Description
path string One of the two Path from mediaList
mediaId string One of the two Or the media ID
includeWords boolean No Also return every word with its timestamps. false by default

Returns:

Field Type Description
mediaId, path string The video transcribed
language string Detected language (ISO 639)
cached boolean true when read back from an earlier transcription
text string The full transcript
segments array One { start, end, text } per sentence, in seconds
words array Only with includeWords: { start, end, text } per word

Cut a video of the library at exact timestamps. Each part is re-encoded (H.264 + AAC, yuv420p, +faststart, rotation applied, original resolution) and added to the library. Give exactly one of cuts or segments.

Parameters:

Field Type Required Description
path string Yes Path of the mp4 from mediaList
cuts number[] One of the two Seconds where to slice: [24.45] gives two parts covering the whole video
segments array One of the two Passages to keep, [{ start, end }]: each becomes a part, in the order given

Every part lasts at least 0.5 s, 20 parts at most, and every timestamp falls inside the video.

Returns duration (of the original) and parts, in order, each with id, path, start, end and duration.


Cut one video of the media library into a series of stories of about the same length: 20 seconds unless another length is asked for, between 10 and 30. The cuts land in a silence of the video when there is one close enough, at even intervals otherwise, and the stories follow each other. The length is a target, not a slice: a few seconds left over are merged into the stories instead of making a tiny last one (2 min 02 at 20 s gives 6 stories of about 20 s; 30 s gives 2 of 15).

Parameters:

Field Type Required Description
videoUrl string Yes URL of the mp4: a path from mediaList, uploadFromUrlTool or confirmUpload, or the URL of a video attached in the chat
targetSeconds number No Target length of each story in seconds, 10 to 30. Default 20
removeSilences boolean No Take the long pauses out of the video before cutting it. Default false: an agent only turns it on when the user explicitly asks to remove the silences, never on its own and never as a suggestion

Returns: duration (of the video cut), silencesRemoved (seconds of silence taken out, 0 when not asked) and stories, in order, each with id, path (the attachment of its own story post), start, end and endsOn: silence (the cut fell in a pause), even (no silence close enough, cut at an even interval) or end (last story).

Each story is then scheduled as its own post with integrationSchedulePostTool: one socialPost per story, in order, exactly one attachment, an empty content and the Instagram setting post_type = story, one minute apart so each is published before the next.

Example:

{ "videoUrl": "https://app.usenadia.com/uploads/2026/10/reel.mp4", "targetSeconds": 15 }

The workspace’s notifications, newest first (the bell of the app): a post published or failed, a channel to reconnect, an email captured by an automation… 100 per page. Read-only.

Parameters: page (integer, optional, 0 = the newest).

Returns: { notifications, total, page, hasMore }. Each notification: id, content (plain text), link, at.


The outgoing webhooks of the workspace and the catalogue of events a webhook can subscribe to. Read-only.

Parameters: webhookId (string, optional, only this one).

Returns: { webhooks, events }. Each webhook: id, name, url, events (empty = every event), integrations (empty = every channel), hasSecret. The signing secret itself is shown once, by webhookManageTool on creation.


Register, test or unregister an outgoing webhook.

Parameters:

Field Type Required Description
action string Yes create, test or delete
webhookId string test, delete The webhook
event string No test: the event to simulate (default: the webhook’s first event, or post.published when it receives all)
name string create
url string create A public HTTPS URL
events string[] No create: the events to receive (empty = all), names from webhooksListTool
integrationIds string[] No create: the channels (empty = all)
confirmationToken string create, delete, second call The token of the first call, once the user said yes

create and delete are confirmed actions: a webhook sends everything it subscribes to (DMs, captured emails…) to its URL for as long as it lives. test acts at once.

Returns: { ok, errors? } plus webhook on creation — with its secret, returned once: deliveries are signed with it (X-Nadia-Signature, HMAC SHA-256 of the body).

test sends one delivery to that webhook only, without any real event: the normal signed envelope with test: true and a sample data (fake test_… ids, nothing is published). It waits for the answer — one attempt, no retry, 10-second timeout — and returns { ok, delivered, status, event, deliveryId }: status is the HTTP status the URL answered, null when nothing answered. Same as POST /public/v1/webhooks/{id}/test.