Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,11 @@ The same applies to anything a self-hoster can switch off or raise: platform ava

### Endpoints, shapes and pagination

`openapi.json` is the source of truth for every operation, request field, response shape and error (hand-written from the app's `routes/api.php`, `app/Http/Requests/Api/**`, `app/Http/Resources/**`, `app/Http/Controllers/Api/**`). Public API = routes whose URI starts with `api/` (83 today: `php artisan route:list --path=api`). Edit the spec, not generated pages. `api-reference/introduction.mdx` covers auth, errors, pagination, rate limits and timestamps; `api-reference/guides/posting.mdx` covers `platforms[].meta` per network, scheduling modes and thread replies; `api-reference/guides/media-uploads.mdx` covers media. Update those, not this file. Facts to keep in mind:
`openapi.json` is the source of truth for every operation, request field, response shape and error (hand-written from the app's `routes/api.php`, `app/Http/Requests/Api/**`, `app/Http/Resources/**`, `app/Http/Controllers/Api/**`). Public API = routes whose URI starts with `api/` (83 today: `php artisan route:list --path=api`). Edit the spec, not generated pages. `api-reference/introduction.mdx` covers auth, errors, pagination, rate limits and timestamps; `api-reference/guides/posting.mdx` covers `meta` per network, scheduling modes and thread replies; `api-reference/guides/media-uploads.mdx` covers media. Update those, not this file. Facts to keep in mind:

- Resources are unwrapped (`JsonResource::withoutWrapping()`); lists use the Laravel envelope `{ data, links, meta }` with the page size from `config('app.pagination.default')` (25 today). Always tell readers to read `meta.per_page`.
- `PUT /posts/{post}` with `status: publishing` publishes now; there is no separate publish endpoint.
- `platforms[].meta` rules live only in the app's `App\Support\PostPlatformMetaRules`; document them from there. Unknown keys are dropped; on update `meta` is merged and `null` clears a nullable key. Boolean meta keys do not accept `null`; send `true` or `false`.
- Post `meta` rules live only in the app's `App\Support\PostPlatformMetaRules`; document them from there. Unknown keys are dropped; on update `meta` is merged and `null` clears a nullable key. Boolean meta keys do not accept `null`; send `true` or `false`.
- There is no asset-library endpoint and no account toggle in the REST API.
- Enum values (statuses, content types, webhook events, platforms) are documented in `openapi.json` schemas; copy them from the app enums under `app/Enums/**`, never from memory.

Expand Down Expand Up @@ -157,6 +157,7 @@ The full table (17 entries, including analytics, retention and Google Business r
- Upload limits: `upload_max_filesize=1G`, `post_max_size=1G` (matches the Docker image)
- Bluesky and Mastodon work without API credentials; every other network needs developer app credentials (Google Business Profile has its own Google client, separate from YouTube)
- Upgrading an existing install to 2.0 needs `php artisan release:trypost-2 --force --include-unsubscribed` after `migrate --force` (self-hosted has no Stripe subscription)
- The release after 2.0 (one channel per post) removes `release:trypost-2`; installs on v1.1.0 must upgrade to v2.0.0 and run it before upgrading further, or the first new migration stops

## Supported Languages

Expand Down
14 changes: 7 additions & 7 deletions ai/tools-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,28 +56,28 @@ A member who needs approval can create and edit posts. When they schedule, queue

| Tool | What it does | Key arguments |
|------|--------------|---------------|
| `list-posts-tool` | List posts, newest scheduled date first. `published` includes partially published posts. Read-only. REST: [List posts](/api-reference/posts/list-posts) | `status` (`draft` \| `scheduled` \| `pending_approval` \| `published` \| `failed`), `search` (substring of the text), `channels[]`, `labels[]`, `untagged`, `page` |
| `get-post-tool` | Get one post: text, media, labels, status, `schedule_mode`, `scheduled_at`, `published_at`, recurrence, approval fields, `origin`, `post_group_id`, and its channel's `content_type`, `meta`, status, error and `platform_url`. Read-only. REST: [Get post](/api-reference/posts/get-post) | `post_id` (required) |
| `create-post-tool` | Create one post on one channel: a draft, a post at a custom time, a queue post (next or top, or one exact free slot), or a post published now. Returns the post. REST: [Create post](/api-reference/posts/create-post) | `platforms[]` (required, exactly one `{social_account_id, content_type?, meta?}`), `content`, `media[]`, `status` (`draft` default \| `scheduled` \| `publishing`), `scheduled_at`, `queue` (`next` \| `top`), `queue_slot`, `label_ids[]` |
| `list-posts-tool` | List posts, newest scheduled date first. Read-only. REST: [List posts](/api-reference/posts/list-posts) | `status` (`draft` \| `scheduled` \| `pending_approval` \| `published` \| `failed`), `search` (substring of the text), `channels[]`, `labels[]`, `untagged`, `page` |
| `get-post-tool` | Get one post: text, media, labels, status, `schedule_mode`, `scheduled_at`, `published_at`, recurrence, approval fields, `origin`, `post_group_id`, and its channel at the top level: `publish_status`, `platform`, `content_type`, `meta`, `error_message`, `platform_url` and `social_account`. Read-only. REST: [Get post](/api-reference/posts/get-post) | `post_id` (required) |
| `create-post-tool` | Create one post on one channel: a draft, a post at a custom time, a queue post (next or top, or one exact free slot), or a post published now. Returns the post. REST: [Create post](/api-reference/posts/create-post) | `social_account_id` (required), `content_type`, `meta`, `content`, `media[]`, `status` (`draft` default \| `scheduled` \| `publishing`), `scheduled_at`, `queue` (`next` \| `top`), `queue_slot`, `label_ids[]` |
| `create-posts-tool` | Create one independent post per destination, as the composer does with several channels; the posts share a `post_group_id`. Each destination may override text, media, type and meta. No `queue_slot` here. Returns `{posts}`. REST: [Create posts in batch](/api-reference/posts/create-posts-in-batch) | `status` (required), `destinations[]` (required: `{social_account_id, content_type?, content?, media?, meta?}`), `content`, `media[]`, `scheduled_at`, `queue`, `label_ids[]` |
| `update-post-tool` | Change a post's text, media (replaces the list), `content_type`, `meta` (merged; `null` clears a key, `thread_replies` replaces the list), status, schedule, queue or labels. The channel itself is fixed. On Pinterest and TikTok, new media re-decides the type when `content_type` is omitted. REST: [Update post](/api-reference/posts/update-post) | `post_id` (required), `content`, `media[]`, `content_type`, `meta`, `status` (`draft` \| `scheduled` \| `publishing`), `scheduled_at`, `queue`, `label_ids[]` |
| `publish-post-tool` | Publish a draft or scheduled post now, at `scheduled_at`, or into the queue. Validated like a scheduled post (text limits, required meta, media rules, thread replies); a failure names the platform and field and nothing is published. Destructive. No single REST operation: REST uses [Update post](/api-reference/posts/update-post) with a status | `post_id` (required), `scheduled_at`, `queue` |
| `approve-post-tool` | Approve a `pending_approval` post. By default it is scheduled as its author asked (queue or requested time); pass a new time or publish now instead. One of them is required when the requested time has passed or the author asked to publish now. Pass one of `scheduled_at` (future, before 2038-01-19) or `publish_now`, not both. Destructive. REST: [Approve post](/api-reference/approvals/approve-post) | `post_id` (required), `scheduled_at`, `publish_now` |
| `reject-post-tool` | Reject a `pending_approval` post. It goes back to drafts and the member who asked is emailed; no reason is stored. REST: [Reject post](/api-reference/approvals/reject-post) | `post_id` (required) |
| `preview-post-tool` | Show the exact text each network gets (X links defused when that is on), next to the original, with length stats. Nothing is truncated. Read-only. REST: [Get post preview](/api-reference/posts/get-post-preview) | `post_id` (required) |
| `preview-post-tool` | Show the exact text the post's network gets (X links defused when that is on), next to the original, with length stats. One object, with `platform` and `content_type` at the top. Nothing is truncated. Read-only. REST: [Get post preview](/api-reference/posts/get-post-preview) | `post_id` (required) |
| `delete-post-tool` | Delete a post from TryPost permanently. It is never removed from the network. Returns `{deleted: true}`. Destructive. REST: [Delete post](/api-reference/posts/delete-post) | `post_id` (required) |
| `attach-media-from-url-tool` | Download files from public URLs and append them to the post. Returns `post`, `attached_count`, `failed_urls` and `failures[]` with a reason (`unreachable`, `type_not_allowed`, `too_large`, `host_not_allowed`). REST: [Attach media from URL](/api-reference/media-and-uploads/attach-media-from-url) | `post_id` (required), `urls[]` (required, 1–10 `{url, alt?}`) |
| `request-media-upload-tool` | Issue a one-time signed URL to upload a local file. Returns `upload_token`, `upload_url`, `expires_at`, `max_bytes`, `max_bytes_by_type` and `field_name` (`media`). Upload with `curl -F media=@file "<upload_url>"`. REST: [Upload to signed URL](/api-reference/media-and-uploads/upload-to-signed-url) | none |
| `attach-media-from-upload-tool` | Append an uploaded file to a post. Returns `{post}`. REST: [Attach media from upload](/api-reference/media-and-uploads/attach-media-from-upload) | `post_id` (required), `upload_token` (required), `alt` |
| `get-post-metrics-tool` | Read the latest saved analytics of a published post per platform (reactions, comments, saves, reach, views, watch time where supported). Values may lag the network until the next analytics run; excluded or unpublished platforms answer `unsupported`. Read-only. REST: [Get post metrics](/api-reference/posts/get-post-metrics) | `post_id` (required) |
| `get-post-metrics-tool` | Read the latest saved analytics of a published post (reactions, comments, saves, reach, views, watch time where supported). Returns one object: `post_id`, `platform`, `publish_status`, `platform_post_id`, `platform_url` and `metrics`. Values may lag the network until the next analytics run; an unpublished post or a network without analytics answers `unsupported`. Read-only. REST: [Get post metrics](/api-reference/posts/get-post-metrics) | `post_id` (required) |
| `list-post-notes-tool` | List a post's notes (internal team comments, never published), newest first. Read-only. REST: [List post notes](/api-reference/post-notes/list-post-notes) | `post_id` (required), `page` |
| `create-post-note-tool` | Add a note. Every other member who has note emails on is emailed; on a pending post, only the approvers and the member who asked. REST: [Create post note](/api-reference/post-notes/create-post-note) | `post_id` (required), `body` (required, max 2000) |
| `update-post-note-tool` | Edit a note. Only its author can. No email is sent. REST: [Update post note](/api-reference/post-notes/update-post-note) | `post_id`, `note_id`, `body` (all required) |
| `delete-post-note-tool` | Delete a note. Only its author can. Destructive. REST: [Delete post note](/api-reference/post-notes/delete-post-note) | `post_id`, `note_id` (both required) |
| `set-post-recurrence-tool` | Make a scheduled post repeat every `interval` days, weeks, months or years, `times` more times, at the same local time in the channel's zone. The last occurrence must be on or before 2037-12-31 23:59:59 UTC. Members who publish directly only. REST: [Set post recurrence](/api-reference/recurrence/set-post-recurrence) | `post_id`, `interval` (1–365), `frequency` (`day` \| `week` \| `month` \| `year`), `times` (1–100), all required |
| `clear-post-recurrence-tool` | Stop a post from repeating. The post and its next time stay. REST: [Remove post recurrence](/api-reference/recurrence/remove-post-recurrence) | `post_id` (required) |

Posts that are `publishing`, `published`, `partially_published` or `failed` cannot be changed or deleted. Notes and recurrence follow [Recurring posts](/knowledge-base/publish/recurring-posts).
Posts that are `publishing`, `published` or `failed` cannot be changed or deleted. Notes and recurrence follow [Recurring posts](/knowledge-base/publish/recurring-posts).

### Before a post can be scheduled or published

Expand Down Expand Up @@ -220,7 +220,7 @@ Any member can manage signatures. A signature is never added to a post on its ow

## Webhooks

Admins only. Each delivery is a JSON `POST` signed with HMAC-SHA256 of the body; the hex digest is in `X-Webhook-Signature`. After 5 failed deliveries in a row the webhook is paused and the account owner is emailed. Events: `post.created`, `post.scheduled`, `post.unscheduled`, `post.published`, `post.partially_published`, `post.failed`, `post.deleted`. See [Webhooks](/knowledge-base/settings/webhooks).
Admins only. Each delivery is a JSON `POST` signed with HMAC-SHA256 of the body; the hex digest is in `X-Webhook-Signature`. After 5 failed deliveries in a row the webhook is paused and the account owner is emailed. Events: `post.created`, `post.scheduled`, `post.unscheduled`, `post.published`, `post.failed`, `post.deleted`. See [Webhooks](/knowledge-base/settings/webhooks).

| Tool | What it does | Key arguments |
|------|--------------|---------------|
Expand Down
7 changes: 3 additions & 4 deletions api-reference/guides/media-uploads.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,8 @@ curl -X POST https://app.trypost.it/api/posts \
{ "upload_token": "4f6c2b1e-8d3a-4e5f-9a7b-1c2d3e4f5a6b" },
{ "id": "9d3c1f30-8a9b-4c0d-9e1f-2a3b4c5d6e7f" }
],
"platforms": [
{ "social_account_id": "7a2e9c14-5b8d-4f3a-b6e1-0c9d8a7f6e52", "content_type": "instagram_feed" }
]
"social_account_id": "7a2e9c14-5b8d-4f3a-b6e1-0c9d8a7f6e52",
"content_type": "instagram_feed"
}'
```

Expand Down Expand Up @@ -186,4 +185,4 @@ Each media item takes optional settings:

## Which posts take media

Media can be added and replaced until the post goes out. Posts that are `publishing`, `published`, `partially_published` or `failed` cannot take media: the API answers `422` with `This post has already been processed and cannot be re-published. Duplicate it to try again.`
Media can be added and replaced until the post goes out. Posts that are `publishing`, `published` or `failed` cannot take media: the API answers `422` with `This post has already been processed and cannot be re-published. Duplicate it to try again.`
Loading