<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: GPTpost</title>
    <description>The latest articles on DEV Community by GPTpost (@gptpost).</description>
    <link>https://dev.to/gptpost</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4135385%2F3b4f99d7-2798-402d-ab44-4c55c5e43604.png</url>
      <title>DEV Community: GPTpost</title>
      <link>https://dev.to/gptpost</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gptpost"/>
    <language>en</language>
    <item>
      <title>Letting an AI agent schedule social posts safely: length checks, approvals and Idempotency-Key</title>
      <dc:creator>GPTpost</dc:creator>
      <pubDate>Tue, 20 Oct 2026 22:57:00 +0000</pubDate>
      <link>https://dev.to/gptpost/letting-an-ai-agent-schedule-social-posts-safely-length-checks-approvals-and-idempotency-key-1iia</link>
      <guid>https://dev.to/gptpost/letting-an-ai-agent-schedule-social-posts-safely-length-checks-approvals-and-idempotency-key-1iia</guid>
      <description>&lt;p&gt;If you let an AI agent post to your social accounts, the scary part is not the writing. It is the retry. A model calls a tool, the network times out, the agent tries again, and now the same announcement is up twice. Or the agent writes 340 characters for a network that allows 300, and you find out at send time, at 9:00 on a Monday.&lt;/p&gt;

&lt;p&gt;We build GPTpost, a social media scheduler for small teams, and we gave it a REST API and a remote MCP server so Claude, ChatGPT and plain scripts can draft and schedule posts. This post is about the guard rails we put in front of agents, because they are useful patterns even if you never use our product.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Agents get the same rules as people
&lt;/h2&gt;

&lt;p&gt;An agent is just another author. Posts it creates go through the same checks as posts written in the app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Length is checked when the post is queued&lt;/strong&gt;, not when it is sent. Bluesky 300, Mastodon 500, X 280. A post that does not fit is refused with HTTP 422, so the agent can shorten it while it still has the context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Approvals still apply.&lt;/strong&gt; If the workspace requires sign-off, the agent can draft and schedule, but nothing goes out unapproved (409 if it tries to skip that).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan limits still apply&lt;/strong&gt; (402), so a runaway loop cannot post past what the workspace pays for.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The point: do not build a separate, looser path for automation. Put the agent behind the rules you already trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Retries must be safe: Idempotency-Key
&lt;/h2&gt;

&lt;p&gt;Every write accepts an &lt;code&gt;Idempotency-Key&lt;/code&gt; header. Send the same key twice and you get the first result back instead of a second post.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://app.oraglegpt.org/api/v1/agent/posts &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$GPTPOST_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Idempotency-Key: launch-2026-11-02-mastodon"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"text":"Hello from my agent","account_ids":["ACCOUNT_ID"],"schedule_at":"2026-11-02T09:00:00Z"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two tips that apply to any API like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Derive the key from &lt;strong&gt;what&lt;/strong&gt; you are posting (campaign, slot, account), not from a random value generated per attempt. A random key per attempt defeats the purpose.&lt;/li&gt;
&lt;li&gt;Keep a small local state file of what you already sent. It makes re-runs boring, which is what you want.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. "Published" should mean confirmed
&lt;/h2&gt;

&lt;p&gt;A scheduler can be wrong in two directions: it can say a post went out when the network silently refused it, or it can resend something that actually landed. We mark a post published only after the network confirms it, and when the answer is unclear we hold it instead of retrying blindly. One duplicate on a brand account costs more trust than one late post.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Scope the key, and expect it to expire
&lt;/h2&gt;

&lt;p&gt;Keys are per workspace, shown once, stored hashed, and carry scopes (&lt;code&gt;accounts:read&lt;/code&gt;, &lt;code&gt;posts:read&lt;/code&gt;, &lt;code&gt;posts:write&lt;/code&gt;, &lt;code&gt;media:write&lt;/code&gt;). A key never has more rights than the person who created it. Give an agent the smallest set it needs, and set an expiry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trying it with Claude Code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http gptpost https://app.oraglegpt.org/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &amp;lt;YOUR_API_KEY&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP tools are &lt;code&gt;whoami&lt;/code&gt;, &lt;code&gt;list_accounts&lt;/code&gt;, &lt;code&gt;create_post&lt;/code&gt;, &lt;code&gt;schedule_post&lt;/code&gt;, &lt;code&gt;publish_post&lt;/code&gt;, &lt;code&gt;upload_media&lt;/code&gt;, &lt;code&gt;get_post_status&lt;/code&gt; and &lt;code&gt;list_posts&lt;/code&gt;. The OpenAPI file at &lt;a href="https://app.oraglegpt.org/openapi.json" rel="noopener noreferrer"&gt;https://app.oraglegpt.org/openapi.json&lt;/a&gt; works for ChatGPT custom actions and OpenAPI-aware agent frameworks.&lt;/p&gt;

&lt;p&gt;Honest limits: GPTpost publishes today to Mastodon, Bluesky, Lemmy, DEV, WordPress, Telegram, Discord, Slack and a few more; Facebook, Instagram, LinkedIn and others open up as each network finishes reviewing the app. There is no social inbox and no listening.&lt;/p&gt;

&lt;p&gt;Docs: &lt;a href="https://app.oraglegpt.org/developers" rel="noopener noreferrer"&gt;https://app.oraglegpt.org/developers&lt;/a&gt;. There is a 14-day trial with no card at &lt;a href="https://oraglegpt.org" rel="noopener noreferrer"&gt;https://oraglegpt.org&lt;/a&gt; if you want to point an agent at a real workspace.&lt;/p&gt;

&lt;p&gt;What guard rails do you put in front of agents that touch public accounts?&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>api</category>
      <category>mcp</category>
    </item>
    <item>
      <title>GPTpost connector live test</title>
      <dc:creator>GPTpost</dc:creator>
      <pubDate>Mon, 21 Sep 2026 09:21:21 +0000</pubDate>
      <link>https://dev.to/gptpost/gptpost-connector-live-test-4d67</link>
      <guid>https://dev.to/gptpost/gptpost-connector-live-test-4d67</guid>
      <description>&lt;p&gt;This article was created and published through GPTpost, a social-media management platform, as a connector test.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
