Skip to content
All docs

GoHighLevel setup

Credential: Private Integration Token

The GoHighLevel connector creates draft blog posts in a sub-account’s blog. They appear in the sub-account’s blog dashboard for you to review and publish.

Step 1 - create a Private Integration Token

Inside the sub-account (not the agency view):

  1. Settings → Private Integrations → Create new Integration.

  2. Name it BirchSeek and tick all seven blogs scopes:

    Scope Used for
    blogs/post.write Creating posts
    blogs/post-update.write Updating posts on a refresh run
    blogs/posts.readonly Finding our own prior post before publishing
    blogs/check-slug.readonly A fast check for whether a slug is free
    blogs/list.readonly Listing your blogs
    blogs/author.readonly Listing authors
    blogs/category.readonly Listing categories
  3. Copy the token. It is shown once.

Miss one of the write or posts.readonly scopes and the connector cannot publish — so the connection test exercises them rather than letting your first article fail at the very last pipeline step.

Rotating the token in GoHighLevel keeps the old one valid for 7 days, so a rotation will not break jobs already queued.

Step 2 - collect four ids

GoHighLevel’s Blogs API takes ids, never names. You need:

Setting Where it comes from
Location ID The sub-account id — it is in the sub-account’s URL
Blog ID Which blog to publish into
Author ID A blog author. The API takes an id, so BirchSeek cannot use a plain name
Category IDs At least one; the API requires a non-empty list

You do not have to hunt for the last three. Save the connector with the token and location id, press Send a test, and the error message lists every blog, author and category in the sub-account with its id. Paste the ones you want and re-test.

GoHighLevel requires imageUrl on every blog post, and BirchSeek generates no cover images. Give the connector one absolute https:// image URL and it is used for every article, along with alt text (which falls back to the article title).

There is no way around this one — a post without it is rejected by their API.

Step 4 - send a test

Send a test walks your blogs, authors and categories, confirms all four configured ids still exist in the sub-account, and reads one row of the post listing to prove the publishing scopes. It reports the blog and author by name.

What BirchSeek writes

Per article, via POST /blogs/posts:

  • title (your SEO title, falling back to the article title), urlSlug, description
  • rawHTML — the article rendered to HTML
  • status: "DRAFT", publishedAt (the intended date; required even for a draft)
  • author, categories, tags, imageUrl, imageAltText
  • wordCount

rawHTML ends with a ## Sources block: a numbered list pairing each verified claim with the page it was checked against, rendered into the HTML like any other section. BirchSeek composes that body once, before any connector sees it, so every connector publishing to your own site writes the same block - there is nothing to append yourself. (A syndicated copy to dev.to, Hashnode or Medium carries the same block, and the canonical link back to your page besides. That copy is not covered by the project setting: those three platforms have no citation field of their own, so the body is the only place the evidence can travel.) The block is on by default, and there is no switch for it in the dashboard: it is a project setting called append_sources_section, and the only way to change it today is PATCH /v1/projects/{id} carrying the whole settings object, because that request replaces the object rather than merging into it.

That last field looks trivial and is not. A PUT without wordCount returns 200, updates everything else, and silently discards the article body — GoHighLevel’s own engineers confirmed this. BirchSeek always sends it, so a refresh run cannot report success while your blog still shows last month’s article.

On a refresh run the post is updated in place, keeping whatever status it currently has — so a post you already published stays published, with the new content.

How BirchSeek finds its own post again

Worth knowing before a publish stops on you, because GoHighLevel is the one connector where this can happen.

BirchSeek finds its prior post by the post id its own last publish returned. That id is the only proof of authorship it has here: CreateBlogPostParams is a closed set of presentation fields, so unlike Shopify, Wix or Webflow there is no metadata bag, no custom property, and no field BirchSeek could quietly mark its own posts with. Every field that could hold one is a field your readers see.

A url slug is not a substitute. It is a string anyone can type into the GoHighLevel blog editor, and the post listing BirchSeek walks contains every post in the blog in every status: your drafts, your scheduled posts and your live pages. So when the id does not resolve and something else is already sitting on this article’s slug, BirchSeek refuses. It does not update that post, because an update here is a full replace of the title, the body, the categories, the tags and the image, and it cannot tell whose post it is. It does not create a second one either, because the slug is taken.

Nothing is sent, and the message names both repairs: if that post is not yours to lose, delete it or give the article a different slug; if it is yours, leave it and give the article a different slug. The cost is one publish, and it is only ever paid where the alternative was overwriting a page.

Two consequences worth stating plainly:

  • Renaming a BirchSeek post’s slug in the GoHighLevel editor is fine. The id still matches, so the next refresh updates that post wherever its slug now points.
  • Reusing a BirchSeek article’s slug on a post of your own is not. That article’s next publish stops until one of the two slugs changes.

Canonical URLs

A GoHighLevel blog is on your domain, so it is the canonical by default and BirchSeek leaves canonicalLink alone.

The optional mirror mode exists for one case: you publish primarily somewhere else and run the GoHighLevel blog as a copy. Turn it on and BirchSeek points each post’s canonical at your primary site. Turn it back off and the override is cleared — a stale canonical would otherwise keep telling Google your own page is a duplicate of a site you no longer publish to.

BirchSeek only offers DRAFT and PUBLISHED. SCHEDULED would hand scheduling to GoHighLevel, which conflicts with BirchSeek’s own publishing calendar, and ARCHIVED is accepted by their API but does not actually archive anything.

Troubleshooting

  • 401/403 - the token was rotated more than 7 days ago, or it is missing a scope. Check all seven from step 1.
  • 422 naming a field - GoHighLevel’s validation messages are unusually good and are passed through verbatim. It is almost always a bad author id, category id or blog id; re-run the connection test to list the valid ones.
  • “gohighlevel refused to list this blog’s posts” - blogs/posts.readonly is missing.
  • “already exists on this blog … Nothing was sent” - a post is already sitting on this article’s url slug, and BirchSeek cannot prove that post is one it wrote. It refuses rather than replace it. Open the post in GoHighLevel and pick a repair: delete it (or rename its slug) if it is not yours to lose, or give the article a different slug if it is. See “How BirchSeek finds its own post again” above.
  • A post appears twice - this should not happen. BirchSeek walks the whole post listing before it creates anything, matches on the id its last publish returned, and refuses on a slug it cannot account for rather than guessing. If two copies do appear, report it.