Post with LangChain

Post to social media
with LangChain.

Wrap PostLake as one tool, or skip the wrapper and connect MCP. Either way the agent sees the same normalised Post response the Publishing docs describe.

Get started free →

Free tier. No card · one API for every network · full MCP access

In shortOne LangChain tool (or MCP) that POSTs /v1/posts. Return the JSON so the agent can read targets[] and decide next steps.

When this guide is for you

You're building a LangChain agent that should post or schedule without registering nine social tools.

Before you start

Same setup the docs quickstart uses. Do this once:

  1. Sign up at app.postlake.dev and verify your email (unlocks free credits).
  2. On Channels, create a profile (e.g. my-brand) and connect at least one account. Bluesky is the fastest first channel: no app review. Instagram/TikTok/Facebook need each platform's review before API posting.
  3. Account menu → API Keys → create a key (sk_live_…). It shows once; treat it like a password.

Working example in LangChain

Connect accounts once in the dashboard, then this is the publish call:

from langchain_core.tools import tool
import os, requests, uuid

@tool
def post_to_social(text: str, platforms: list[str] | None = None) -> dict:
    """Publish via PostLake. Returns the full Post object (check targets[])."""
    body = {"text": text, "profile": "my-brand"}
    if platforms:
        body["platforms"] = platforms  # filter only
    r = requests.post(
        "https://api.postlake.dev/v1/posts",
        headers={
            "Authorization": f"Bearer {os.environ['POSTLAKE_API_KEY']}",
            "Idempotency-Key": str(uuid.uuid4()),
        },
        json=body,
    )
    r.raise_for_status()
    return r.json()

# model.bind_tools([post_to_social]), or use MCP instead (no wrapper)

Make it work in LangChain

Tool-specific glue on top of the shared setup above:

  1. Prefer MCP (https://api.postlake.dev/mcp) if your LangChain host supports it, OAuth. No key in the tool.
  2. Otherwise define one tool that POSTs /v1/posts and returns the full JSON (not just "ok").
  3. Instruct the agent to read state and each targets[].state before claiming success.
  4. Always set Idempotency-Key (new UUID per logical post) so tool retries don't double-post.

Read the response (don't skip this)

You get one Post with an overall state and a targets[] array. One entry per account. Always check each target; partial success is normal.

{
  "id": "post_a1b2c3",
  "state": "partial",
  "targets": [
    { "platform": "bluesky",  "state": "published", "url": "https://bsky.app/…" },
    { "platform": "linkedin", "state": "failed",
      "error": { "type": "invalid_request", "message": "…", "retryable": false } }
  ]
}

Where the post goes

Same rules as the docs. Pick one addressing style:

See Publishing: where to post.

Do more (same API)

Pitfalls specific to this path

Want zero wrapper code? Connect the hosted MCP server (https://api.postlake.dev/mcp) over OAuth. Same accounts and responses as this API path. Agents overview.

Common questions

How do I let a LangChain agent post to social media?

Either connect PostLake MCP, or bind one tool that POSTs /v1/posts with text + profile and returns the JSON. The agent then handles every connected network through that one tool.

Do I need a tool per social network?

No. One tool calling PostLake covers the profile. Use platforms only as an optional filter.

Can LangChain use PostLake over MCP?

Yes. Point the host at https://api.postlake.dev/mcp and complete OAuth. Tools for publish, schedule, validate, and analytics appear without a custom wrapper.

Go deeper in the docs

These guides stay short on purpose. Canonical behaviour lives here:

Also: Media · Errors · MCP · Analytics

Related guides

All guides · Full docs · llms.txt · Markdown

Stuck? The docs are the source of truth, start at Publishing.

Open the dashboard →