Skip to content

Commit 4399e88

Browse files
committed
Cloud Browser instead of the connect page: sign in once in your own Chrome in the cloud and enable the app for agents; browser_url in errors; pay-as-you-go pricing from the site
1 parent 84e8d80 commit 4399e88

2 files changed

Lines changed: 20 additions & 25 deletions

File tree

‎README.md‎

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
**Substack API** for Python scripts and a hosted **Substack MCP server** for Claude, ChatGPT, Cursor, Codex and n8n. Turn Markdown files into Substack drafts, schedule posts and Notes, export subscribers and posts, reply to comments you have not answered and pull subscriber, revenue and post stats from your own Substack publication.
44

5-
Substack has only a limited official API and no official MCP server. This repo gives you both, on top of the **hosted Substack API by [Cotlet](https://cotlet.dev/integrations/substack-api-mcp-server)**: you sign in to Substack once in your browser, Cotlet keeps the session working, and your AI agent (over MCP) or the Python scripts here (over the REST API) work in your account with one API key.
5+
Substack has only a limited official API and no official MCP server. This repo gives you both, on top of the **hosted Substack API by [Cotlet](https://cotlet.dev/integrations/substack-api-mcp-server)**: you sign in to Substack once in your own Cloud Browser (a Chrome Cotlet runs for you in the cloud), Cotlet keeps you signed in 24/7, and your AI agent (over MCP) or the Python scripts here (over the REST API) work in your account with one API key.
66

77
- **Substack MCP server:** `https://cotlet.dev/mcp/v1`, 14 Substack tools for your AI agent. [Setup](#substack-mcp-server-for-claude-chatgpt-cursor-and-codex)
88
- **Substack API:** `https://cotlet.dev/api/v1/substack/{endpoint}`, plus 15 ready Python scripts, one file per job, standard library only. [Scripts](#scripts)
@@ -39,11 +39,11 @@ python schedule_post.py --file essay.md --at 2026-10-14T08:00:00-04:00
3939
## How it works
4040

4141
```text
42-
your script / AI agent ──HTTPS──▶ Cotlet Substack API ──your session──▶ substack.com (your publication)
42+
your script / AI agent ──HTTPS──▶ Cotlet Substack API ──your Cloud Browser's IP and cookies──▶ substack.com (your publication)
4343
```
4444

45-
1. **Get an API key.** [Request access at cotlet.dev](https://cotlet.dev/app/signup?app=substack) with Substack selected. Each request is reviewed and the key arrives by email. Every account starts with a free 7-day trial and 5,000 credits, no card needed.
46-
2. **Connect Substack once.** In the Cotlet console, open the Substack connect page and sign in to Substack the way you always do. Cotlet keeps the session, never your password.
45+
1. **Get an API key.** [Request access at cotlet.dev](https://cotlet.dev/app/signup?app=substack) with Substack selected. Each request is reviewed and the key arrives by email. Every account starts with a free 7-day trial and 2,000 credits, no card needed.
46+
2. **Sign in to Substack once.** In the Cotlet console, open your Cloud Browser, sign in to Substack there the way you always do, and press **Enable for agents** (read only or read and write). Password saving is off, so Cotlet never saves your password.
4747
3. **Run the scripts.** Each one is a plain `POST https://cotlet.dev/api/v1/substack/{endpoint}` with your key. When Substack changes its site, Cotlet fixes the integration; these scripts keep working unchanged.
4848

4949
Without a key, or before your access is active, the API answers `403` with a link to request access.
@@ -53,7 +53,7 @@ Without a key, or before your access is active, the API answers `403` with a lin
5353
### Requirements
5454

5555
- Python 3.9 or newer. No `pip install`: the scripts use only the standard library.
56-
- A Cotlet API key with Substack connected.
56+
- A Cotlet API key, with Substack enabled for agents in your Cloud Browser.
5757
- A Substack account that can publish to the publication. The scripts can do what that account can do there.
5858

5959
### Setup
@@ -217,10 +217,10 @@ curl -X POST https://cotlet.dev/api/v1/substack/list_posts \
217217
| Status | Code | What to do |
218218
|---|---|---|
219219
| 403 | `api_key_required`, `access_not_granted` | Set `COTLET_API_KEY`, or [request access to Substack](https://cotlet.dev/app/signup?app=substack). |
220-
| 409 | `AUTH_REQUIRED`, `AUTH_EXPIRED` | Substack is not connected or the session expired. Open the link in the error and sign in again. |
221-
| 409 | `CAPTCHA_REQUIRED`, `MFA_REQUIRED` | Substack asked for a check only you can pass. Finish it on the connect page. |
222-
| 403 | `SCOPE_DENIED` | You connected Substack read-only. Allow write access in the dashboard. |
223-
| 402 | `insufficient_credits` | Credits ran out. Wait for next month's or move to a bigger size. |
220+
| 403 | `AUTH_REQUIRED`, `AUTH_EXPIRED` | Substack is not signed in or not enabled for agents, or it signed you out. Open the `browser_url` in the error, sign in to Substack in your Cloud Browser and enable it. |
221+
| 403 | `CAPTCHA_REQUIRED`, `MFA_REQUIRED` | Substack asked for a check only you can pass. Finish it in your Cloud Browser at the `browser_url`. |
222+
| 403 | `SCOPE_DENIED` | You enabled Substack read only. Switch it to read and write in your Cloud Browser. |
223+
| 402 | `INSUFFICIENT_CREDITS` | Credits ran out. Buy a credit pack in the dashboard. |
224224
| 429 | `rate_limited` | The client waits for `Retry-After` and retries by itself. |
225225
| 503 | `TARGET_BLOCKED` | Substack changed something; the endpoint is paused until it is fixed. Credits are refunded. |
226226

@@ -242,13 +242,13 @@ Yes: `python export_subscribers.py --out subscribers.csv` gives the same CSV as
242242
Yes: `python export_posts.py --dir posts` writes one `.md` file per post, including the paywalled part of your own posts. Drafts too, with `--status draft`.
243243

244244
**Is this a Substack scraper?**
245-
It does what people usually want a scraper for (export posts, subscribers and stats) but works differently: the scripts call a hosted API that acts in your own Substack account with your own session. There is no headless browser on your machine, no `substack.sid` cookie to copy from DevTools and nothing to fix when Substack updates its site. It works on your own publication, not on other people's.
245+
It does what people usually want a scraper for (export posts, subscribers and stats) but works differently: the scripts call a hosted API that acts in your own Substack account, signed in inside your own Cloud Browser. There is no headless browser on your machine, no `substack.sid` cookie to copy from DevTools and nothing to fix when Substack updates its site. It works on your own publication, not on other people's.
246246

247247
**Do I have to copy cookies or my Substack password into a config file?**
248-
No. You sign in to Substack once in your browser on the Cotlet connect page. Cotlet stores only the session, encrypted, and never your password. Your scripts only ever hold the Cotlet API key.
248+
No. You sign in to Substack once in your own Cotlet Cloud Browser, and enable it for agents. Password saving is off there, so Cotlet never saves your password. Your scripts only ever hold the Cotlet API key.
249249

250-
**What happens when my Substack session expires?**
251-
The call returns `AUTH_EXPIRED` with a link. Open it, sign in to Substack again, and rerun the script.
250+
**What happens when Substack signs me out?**
251+
The call returns `AUTH_EXPIRED` with a link to your Cloud Browser, and you get an email. Sign in to Substack there again and rerun the script.
252252

253253
**Does it need a paid Substack plan?**
254254
No. It acts as the Substack account you sign in with and can do what that account can do in the publication. Paid stats such as churn and revenue exist only for publications with paid subscriptions.
@@ -282,22 +282,17 @@ Email [contact@cotlet.dev](mailto:contact@cotlet.dev) with the `X-Request-Id` fr
282282

283283
## Pricing
284284

285-
Free 7-day trial with 5,000 credits, no card needed. Then one plan for every app Cotlet supports, Substack included:
285+
Free 7-day trial with 2,000 credits, no card needed. Then pay as you go, no subscription: one-time credit packs from $29 for 5,000 credits, valid 12 months, for every app Cotlet supports, Substack included.
286286

287-
| Size | Price | Credits / month |
288-
|---|---|---|
289-
| Solo | $29/mo | 3,000 |
290-
| Pro | $99/mo | 12,000 |
291-
| Agency | $299/mo | 40,000 |
292-
293-
Each successful call uses credits for the work it takes; failed calls cost nothing. Each month's credits stay valid for 3 months. Nothing is charged until your access is active. [Full pricing](https://cotlet.dev/pricing).
287+
A successful call uses 20 to 30 credits (25 for most tools); failed calls cost nothing. Your Cloud Browser uses 50 credits a day while it has an app enabled for agents, however many apps that is. Nothing is charged without a purchase. [Full pricing](https://cotlet.dev/pricing).
294288

295289
## Security and your Substack account
296290

297-
- **No password stored.** You sign in to Substack yourself; Cotlet keeps only the session, encrypted with AES-256 in an EU vault.
298-
- **Scoped access.** Connect Substack read-only, or read and write.
291+
- **No password saved.** You sign in to Substack yourself, in your own Cloud Browser in the EU, where password saving is off. Its profile is stored encrypted with AES-256-GCM.
292+
- **Every background request listed.** Cotlet sends the same requests your browser would, from its IP with its cookies, and lists each one in your Background activity.
293+
- **Scoped access.** Enable Substack for agents read only, or read and write.
299294
- **Your OK first.** Scheduled and published posts, Notes, replies and new subscribers wait for your confirmation unless you switch that off per tool.
300-
- **Revoke in one click.** Disconnect Substack in the dashboard and the session is deleted.
295+
- **Cut access in one click.** Disable Substack for agents, sign out of it in your Cloud Browser, or reset the browser.
301296
- **No data kept.** Results pass through to your script and are not stored.
302297
- **Never:** CAPTCHA solving, MFA bypass, spam.
303298

‎cotlet_client.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def __init__(self, status: int, body: dict[str, Any]):
3535
self.status = status
3636
self.code = body.get("error", "unknown_error")
3737
self.body = body
38-
link = body.get("connect_url") or body.get("request_access_url") or body.get("docs_url")
38+
link = body.get("browser_url") or body.get("connect_url") or body.get("request_access_url") or body.get("docs_url")
3939
message = body.get("message", "The request failed.")
4040
super().__init__(f"{self.code}: {message}" + (f"\n -> {link}" if link else ""))
4141

0 commit comments

Comments
 (0)