Projects
8 endpoints for projects, with parameters and a real response example.
POST/projects/{id}/pillars
Create a content pillar
Creates one of the territories the account talks about. A slot can fix a pillar, and the autopilot picks one when the slot does not.
| Parameter | In | Type | Description |
|---|---|---|---|
idrequired | path | stringmax 200 chars | Opaque id from a previous response. Do not build one: an id that is not a valid identifier is refused with invalid_input, and one that belongs to another workspace with not_found. |
titlerequired | body | stringmax 120 chars | The pillar's name, up to 120 characters. It is what shows inside the slot's card. |
description | body | stringmax 2000 chars | What this territory covers, up to 2000 characters. The agent reads it as the pillar's boundary, so a blank one is legitimate but leaves it guessing. |
Response
{
"pillar": {
"id": "3f0a1c62-58b1-4e9e-9f4e-2a1d7b0c9e41",
"title": "Numbers that pay the bills",
"description": "Revenue, cost and margin, always with the math behind the number."
},
"created": true
}PATCH/projects/{id}/pillars/{pillarId}
Update a content pillar
Changes a pillar's name or description.
| Parameter | In | Type | Description |
|---|---|---|---|
idrequired | path | stringmax 200 chars | Opaque id from a previous response. Do not build one: an id that is not a valid identifier is refused with invalid_input, and one that belongs to another workspace with not_found. |
pillarIdrequired | path | stringmax 200 chars | Opaque id from a previous response. Do not build one: an id that is not a valid identifier is refused with invalid_input, and one that belongs to another workspace with not_found. |
titlerequired | body | stringmax 120 chars | The pillar's name, up to 120 characters. |
description | body | stringmax 2000 chars | What this territory covers, up to 2000 characters. |
Response
{
"pillar": {
"id": "3f0a1c62-58b1-4e9e-9f4e-2a1d7b0c9e41",
"title": "Numbers that pay the bills",
"description": "Revenue, cost and margin, always with the math behind the number."
},
"created": false
}DELETE/projects/{id}/pillars/{pillarId}
Remove a content pillar
Takes the pillar off the list WITHOUT deleting it: pieces that already spoke about it keep pointing to it, and deleting would leave the history not knowing what each one was about. Slots that were fixed to this pillar go back to being free, and the response says how many.
| Parameter | In | Type | Description |
|---|---|---|---|
idrequired | path | stringmax 200 chars | Opaque id from a previous response. Do not build one: an id that is not a valid identifier is refused with invalid_input, and one that belongs to another workspace with not_found. |
pillarIdrequired | path | stringmax 200 chars | Opaque id from a previous response. Do not build one: an id that is not a valid identifier is refused with invalid_input, and one that belongs to another workspace with not_found. |
Response
{
"pillarId": "3f0a1c62-58b1-4e9e-9f4e-2a1d7b0c9e41",
"slotsLiberados": 2
}POST/projects/{id}/pillars/suggest
Suggest content pillars
Reads the account's own published content and writes up to four suggested pillars. Does nothing when the project already has pillars, including hidden ones: this is a first fill, not a reset. Takes a few seconds, since it reads the account before answering.
| Parameter | In | Type | Description |
|---|---|---|---|
idrequired | path | stringmax 200 chars | Opaque id from a previous response. Do not build one: an id that is not a valid identifier is refused with invalid_input, and one that belongs to another workspace with not_found. |
Response
{
"pillars": [
{
"id": "3f0a1c62-58b1-4e9e-9f4e-2a1d7b0c9e41",
"title": "Numbers that pay the bills",
"description": "Revenue, cost and margin, always with the math behind the number."
}
],
"created": 4
}GET/projects
List projects
Lists the account's projects, with each one's Instagram handle, how many projects the plan allows, and whether another one still fits.
Response
{
"projects": [
{
"id": "c85848ba-2881-4a2e-9bdd-841b26d07359",
"name": "Projeto de teste",
"instagram": null,
"createdAt": "2026-07-31T14:29:14.237659+00:00"
}
],
"limit": 1,
"canCreateMore": false
}POST/projects
Create a project
Creates a new project. A project is an Instagram account with its own brand. Born without brand DNA and without Instagram connected; rejected when the plan's project limit is already reached.
| Parameter | In | Type | Description |
|---|---|---|---|
namerequired | body | stringmax 120 chars | The project's display name in the app, up to 120 characters. It is not the profile name that signs the artwork: that one lives in the brand DNA. |
timezone | body | stringmax 100 chars | IANA, e.g. America/Sao_Paulo. Without it, born in Sao Paulo. It decides what hour an autopilot slot means. |
Response
{
"projectId": "f1c2a9d7-5b3e-4a10-8c6d-2e9b7f403a55",
"name": "Segundo projeto",
"needsBrandDna": true,
"total": 2,
"limit": 3
}PATCH/projects/{id}
Rename a project or change its timezone
Changes a project's display name in the app, its timezone, or both. The name does not touch the profile name inside the brand DNA, which signs the posts' artwork. The timezone is where every autopilot slot hour is read: changing it moves the whole grid, and posts already scheduled keep their time.
| Parameter | In | Type | Description |
|---|---|---|---|
idrequired | path | stringmax 200 chars | Opaque id from a previous response. Do not build one: an id that is not a valid identifier is refused with invalid_input, and one that belongs to another workspace with not_found. |
name | body | stringmax 120 chars | The new display name, up to 120 characters. |
timezone | body | stringmax 100 chars | IANA, e.g. America/Sao_Paulo. Every autopilot slot hour is read in it, so changing it moves the whole grid. Posts already scheduled keep their time. |
Response
{
"projectId": "c85848ba-2881-4a2e-9bdd-841b26d07359",
"from": "Projeto de teste",
"to": "Projeto de teste",
"unchanged": true
}GET/projects/{id}/avatar
Get the project's avatar
Returns the project's avatar for the narrated reels: null when the project has no avatar (a Posttar voice is used instead), otherwise its kind (custom, made from a description, or clone, made from the person's own face and voice), its state, whether it has a face and a voice and whether each is ready (hasFace, hasVoice, faceReady, voiceReady), and up to five photos as 1-hour signed URLs. reactClips lists the reactions and endings recorded for react_video (id, kind: reaction or cta, state, durationSeconds): the ids that PATCH /posts/{id}/react accepts. Read-only: creating, completing or deleting the avatar, and recording reactions, is done in the app, under Strategy, Avatar for Reels.
| Parameter | In | Type | Description |
|---|---|---|---|
idrequired | path | stringmax 200 chars | Opaque id from a previous response. Do not build one: an id that is not a valid identifier is refused with invalid_input, and one that belongs to another workspace with not_found. |
Response
{
"projectId": "0c6f3b7e-2a51-4f0e-9d7a-1f2e3d4c5b6a",
"avatar": {
"kind": "clone",
"state": "ready",
"hasFace": true,
"hasVoice": true,
"faceReady": true,
"voiceReady": true,
"photos": [
"https://..."
]
},
"reactClips": [
{
"id": "6f1c2a9e-3b7d-4e21-9a55-0c8d4f2b7e10",