Landing page API
Create a PG Hero landing page from your own tools: an email sequencer, your CRM, Zapier, Clay, n8n, or Claude. Send a prospect's website and, if you have them, the person and their role. PG Hero researches the company and writes a page for that buyer in your brand, the same way it does in the app, and gives you back a link to put in your email.
Pages made through the API carry your AE's name and booking link, show up in PG Hero like any other page, and send the same view, click and follow-up alerts.
1. Get an API key
An owner or admin creates keys under Settings → Organization → API keys. The key is shown once, so store it somewhere safe, like your tool's secrets. Give each tool its own key and revoke any you stop using. A key works until it's revoked, or until the person who created it leaves your company or stops being an admin, so nobody keeps access after they've gone.
Send the key on every request:
Authorization: Bearer pgh_live_…
If your tool can only set a plain header, X-API-Key: pgh_live_… works too. Check a key with GET /api/v1/me:
curl https://pghero.co.uk/api/v1/me -H "Authorization: Bearer $PGHERO_API_KEY"
{
"organization": { "id": "…", "name": "Your Company" },
"key": { "name": "Outreach sequence", "prefix": "pgh_live_ab12" },
"limits": { "pages_per_24h": 500, "pages_used_24h": 37, "pages_remaining_24h": 463, "review_required": false }
}2. Create a page
POST /api/v1/pages
curl https://pghero.co.uk/api/v1/pages \
-H "Authorization: Bearer $PGHERO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"company": { "website": "fernhollow.coffee" },
"contact": {
"name": "Jess Moore",
"email": "jess@fernhollow.coffee",
"role": "Head of Operations"
},
"owner_email": "sam@yourcompany.com",
"cta_url": "https://cal.com/sam/20min",
"external_id": "outreach-prospect-48213"
}'| Field | Description |
|---|---|
| company.website | Required. The prospect company's website. An account you already have for that domain is reused; otherwise a new one is created and researched. |
| company.name | Optional. Read from their site when you leave it out. |
| contact | Optional: name, email, role, linkedin_url. Needs a name or an email. The page is written for this person's role. Matched to an existing contact by email, then by name. |
| buyer_role | Optional. Who to write for when there's no specific person, e.g. "Head of Operations". Matched to a buyer type in your brand, or added as one. |
| persona_id | Optional. A buyer type id from your brand, instead of buyer_role. |
| owner_email | Optional. The AE who owns the account: their name, photo and booking link go on the page and they get its alerts. Defaults to the account's owner in PG Hero, then to whoever created the key. |
| cta_url | Optional. Where the page's main button goes, e.g. the AE's booking link. https:, mailto: or tel:. |
| feature_ids | Optional. Limit the page to these features of your product. |
| layout | Optional. clean, split, showcase, bold or editorial. Chosen from your brand when left out. |
| review | Optional, default false. true holds the page until its AE approves it in PG Hero. |
| external_id | Optional, recommended. Your own id for this page, such as the prospect id in your sequencer. Sending the same external_id again returns the existing page (status 200) instead of making a second one, so retries are safe. |
| title | Optional. The page's name inside PG Hero. |
The response comes back straight away with 201 Created and the page's url:
HTTP/1.1 201 Created
{
"id": "6f0c2d1e-…",
"object": "page",
"url": "https://pghero.co.uk/v/fernhollow-coffee-jess-moore-x1k29d0a",
"status": "writing",
"review_required": false,
"title": "Fernhollow Coffee · Jess Moore",
"headline": null,
"error": null,
"company": { "id": "9a1b…", "name": "Fernhollow Coffee", "website": "https://fernhollow.coffee" },
"contact": { "id": "c2d3…", "name": "Jess Moore", "email": "jess@fernhollow.coffee", "role": "Head of Operations" },
"owner": { "name": "Sam Carter", "email": "sam@yourcompany.com" },
"external_id": "outreach-prospect-48213",
"source": "api",
"app_url": "https://pghero.co.uk/variant/6f0c2d1e-…",
"created_at": "2026-09-29T09:14:03+00:00",
"updated_at": "2026-09-29T09:14:03+00:00"
}3. Wait for it to be ready
Writing a page usually takes a minute or two. The url works from the start: until the page is written it shows a short holding screen that refreshes itself, so a prospect who clicks early isn't met by an error. Still, send the link once the page is ready.
| status | Meaning |
|---|---|
| writing | Queued or being written. The URL shows the holding screen. |
| awaiting_review | Written, and waiting for its AE to approve it in PG Hero. Only when review was asked for. |
| ready | Written and live. Send the link. Views, clicks and alerts are tracked from now on. |
| failed | Couldn't be written; error says why. Try again with a new external_id, or regenerate it in PG Hero. |
Option A: the page.ready webhook
Set an events webhook URL under Settings → Organization → Notifications & integrations. When an API page is ready to send, PG Hero posts:
POST <your events webhook URL>
X-PGHero-Timestamp: 1759137243
X-PGHero-Signature-V2: sha256=<hex hmac over "<timestamp>.<body>">
{
"event": "page.ready",
"occurred_at": "2026-09-29T09:15:41+00:00",
"page": { "id": "6f0c2d1e-…", "url": "https://pghero.co.uk/v/…", "status": "ready", "external_id": "outreach-prospect-48213", … }
}page.failed is sent the same way. Both are signed like every other event; see verifying the signature. A page held for review fires page.ready when its AE approves it.
Option B: poll
curl https://pghero.co.uk/api/v1/pages/6f0c2d1e-… \ -H "Authorization: Bearer $PGHERO_API_KEY"
Every 15 to 30 seconds is plenty. To find a page by your own id: GET /api/v1/pages?external_id=….
curl "https://pghero.co.uk/api/v1/pages?external_id=outreach-prospect-48213" \ -H "Authorization: Bearer $PGHERO_API_KEY"
GET /api/v1/pages on its own lists your company's pages, newest first, including ones made in the app. It takes limit (up to 100) and offset.
Using it with a sequencer
The usual pattern, in Zapier, Make, n8n, Clay or your sequencer's own webhooks:
- When a prospect is added to a sequence, call
POST /api/v1/pageswith their company website, name, role and email, and their id asexternal_id. - Save the returned
urlto a custom field on the prospect, such aspghero_page. - Put that field in the email: "I put together a page for Fernhollow: {{pghero_page}}".
- Make the first step wait until the page is ready: either trigger it from
page.ready, or start the sequence with a delay of five minutes or more.
When the prospect opens it, the AE gets the usual alert, and the events webhook can write the view back to your CRM.
Claude connector
PG Hero is also an MCP server, so Claude can make pages for you: "make a PG Hero page for the Head of Operations at fernhollow.coffee and give me the link." It uses the same API key and the same rules as the REST API. The server is at https://pghero.co.uk/mcp and offers four tools: create_landing_page, get_landing_page, list_landing_pages and get_page_allowance.
Claude Code
claude mcp add --transport http pghero https://pghero.co.uk/mcp \ --header "Authorization: Bearer pgh_live_…"
Claude Desktop
Add this to claude_desktop_config.json (Settings → Developer → Edit config), then restart Claude:
{
"mcpServers": {
"pghero": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://pghero.co.uk/mcp", "--header", "Authorization:${PGHERO_AUTH}"],
"env": { "PGHERO_AUTH": "Bearer pgh_live_…" }
}
}
}Any other MCP client that can send an Authorization header can connect the same way. A listing in Claude's connector directory, where you'd sign in instead of pasting a key, is on the way.
Limits
- Pages per day: 500 pages through the API and the Claude connector in any 24 hours, per company.
GET /api/v1/meshows what's left. Ask PG Hero if you need more. - Requests: 60 page creations and 300 page reads a minute per key.
- Going over either returns
429. Wait and retry; with anexternal_id, a retry can never make a duplicate.
Errors
Errors have a stable code and a message you can show a person:
HTTP/1.1 400 Bad Request
{ "error": { "code": "invalid_website", "message": "The company website should look like acme.com." } }| code | HTTP | What to do |
|---|---|---|
| missing_api_key / invalid_api_key | 401 | Check the key is sent and hasn’t been revoked. |
| key_disabled | 401 | Its creator is no longer an admin. An admin creates a new key. |
| organization_inactive | 403 | Your PG Hero account is paused. Talk to PG Hero. |
| api_disabled | 403 | The API is switched off for your company. Ask PG Hero to turn it on. |
| invalid_website | 400 | Send a real, public website for the company. |
| invalid_cta_url | 400 | Use an https:, mailto: or tel: link. |
| unknown_owner | 400 | owner_email must be an active PG Hero user in your company. |
| unknown_persona / unknown_feature | 404 | Use ids from your brand in PG Hero. |
| page_not_found | 404 | No page with that id in your company. |
| brand_not_set_up | 409 | Finish your brand in PG Hero first; pages are written from it. |
| daily_limit / rate_limited | 429 | Wait and retry, or ask PG Hero to raise the daily limit. |
| (validation) | 422 | The body didn't match the schema; detail lists each field. |
OpenAPI spec
The full spec is at https://pghero.co.uk/api/v1/openapi.json, for importing into Postman, Zapier, n8n or a custom GPT action.
Questions, or need an endpoint that isn't here? Ask your PG Hero contact.