openapi: 3.0.3
info:
  title: 'GenPage API Reference'
  description: 'Push leads into GenPage, read the personalised pages it generates, and keep your own system in sync.'
  version: 1.0.0
servers:
  -
    url: 'https://backend.genpage.ai'
tags:
  -
    name: Account
    description: ''
  -
    name: Audiences
    description: ''
  -
    name: Authentication
    description: ''
  -
    name: GenPages
    description: ''
  -
    name: Leads
    description: ''
  -
    name: Workspaces
    description: ''
  -
    name: Zapier
    description: ''
components:
  securitySchemes:
    default:
      type: http
      scheme: bearer
      description: "Generate a key in the GenPage dashboard under <b>Settings &rarr; Integrations</b>. A key only works on the workspace it was created for.\n            <br><br>\n            There is a second way in. AI assistants connect through the GenPage MCP server, which authenticates with <b>OAuth 2.1</b> rather than a key: the\n            assistant sends you to GenPage, you pick a workspace and approve, and it receives a token scoped to that one workspace. Every endpoint below\n            accepts either credential, and both are subject to the same workspace binding — so an OAuth token cannot reach a workspace you did not choose\n            at consent, exactly as a key cannot reach one it was not created for."
security:
  -
    default: []
paths:
  /api/external/v1/account/credits:
    get:
      summary: 'Get the credit balance for a workspace.'
      operationId: getTheCreditBalanceForAWorkspace
      description: "Enrichment and AI generation spend credits, so an integration can check\nwhat is left before starting work that would fail part-way through.\n\nCredits are pooled across an account: `remaining` is what the whole pool\nhas left, while `workspace_used` and `workspace_limit` describe this one\nworkspace's share of it. A null `workspace_limit` means uncapped — the\nworkspace can draw on the whole pool."
      parameters:
        -
          in: query
          name: workspace_id
          description: 'The workspace to report on.'
          example: 55
          required: true
          schema:
            type: integer
            description: 'The workspace to report on.'
            example: 55
            nullable: false
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  plan: scale
                  remaining: 4200
                  workspace_used: 800
                  workspace_limit: null
                  renews_at: '2026-09-01 00:00:00'
                properties:
                  plan:
                    type: string
                    example: scale
                  remaining:
                    type: integer
                    example: 4200
                  workspace_used:
                    type: integer
                    example: 800
                  workspace_limit:
                    type: string
                    example: null
                  renews_at:
                    type: string
                    example: '2026-09-01 00:00:00'
        403:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Workspace not found or you do not have permission to access this workspace.'
                properties:
                  message:
                    type: string
                    example: 'Workspace not found or you do not have permission to access this workspace.'
      tags:
        - Account
  /api/external/v1/audiences/get-list:
    get:
      summary: 'Get the list of audiences.'
      operationId: getTheListOfAudiences
      description: "This endpoint is used to get the list of audiences.\n\nAudience `0` is the built-in \"Default Audience\": every lead in the\nworkspace that has not been added to an audience of its own."
      parameters:
        -
          in: query
          name: workspace_id
          description: 'The workspace to list audiences for.'
          example: 55
          required: true
          schema:
            type: integer
            description: 'The workspace to list audiences for.'
            example: 55
            nullable: false
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                example:
                  -
                    id: 0
                    name: 'Default Audience'
                    description: 'Leads that have not been added to a specific audience'
                    color: null
                    lead_count: 12
                    project_id: 55
                    created_at: '2025-01-01T00:00:00.000000Z'
                    updated_at: '2025-01-01T00:00:00.000000Z'
                  -
                    id: 1
                    name: 'Enterprise prospects'
                    description: null
                    color: '#4F46E5'
                    lead_count: 340
                    project_id: 55
                    created_at: '2026-08-01T10:00:00.000000Z'
                    updated_at: '2026-08-01T10:00:00.000000Z'
        401:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: Unauthenticated.
                properties:
                  message:
                    type: string
                    example: Unauthenticated.
        403:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Workspace not found or you do not have permission to access this workspace.'
                properties:
                  message:
                    type: string
                    example: 'Workspace not found or you do not have permission to access this workspace.'
      tags:
        - Audiences
  /api/external/v1/audiences/create:
    post:
      summary: 'Create an audience.'
      operationId: createAnAudience
      description: "An audience is a named segment of leads. Create one to group leads before\ngenerating pages for them, or to keep a list you can link to a campaign."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  audience_id: 44
                  name: 'Enterprise prospects'
                  description: 'Q3 outbound list'
                  lead_count: 2
                properties:
                  audience_id:
                    type: integer
                    example: 44
                  name:
                    type: string
                    example: 'Enterprise prospects'
                  description:
                    type: string
                    example: 'Q3 outbound list'
                  lead_count:
                    type: integer
                    example: 2
      tags:
        - Audiences
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                workspace_id:
                  type: integer
                  description: 'The workspace to create it in.'
                  example: 55
                  nullable: false
                name:
                  type: string
                  description: 'What to call it.'
                  example: 'Enterprise prospects'
                  nullable: false
                description:
                  type: string
                  description: 'Optional note.'
                  example: 'Q3 outbound list'
                  nullable: true
                color:
                  type: string
                  description: 'Optional hex colour for the dashboard.'
                  example: '#4F46E5'
                  nullable: true
                lead_ids:
                  type: array
                  description: 'Leads to put in it immediately.'
                  example:
                    - 56789
                    - 56790
                  items:
                    type: integer
              required:
                - workspace_id
                - name
  /api/external/v1/audiences/add-leads:
    post:
      summary: 'Add leads to an audience.'
      operationId: addLeadsToAnAudience
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  audience_id: 44
                  added: 1
                  skipped: 0
                  lead_count: 3
                properties:
                  audience_id:
                    type: integer
                    example: 44
                  added:
                    type: integer
                    example: 1
                  skipped:
                    type: integer
                    example: 0
                  lead_count:
                    type: integer
                    example: 3
      tags:
        - Audiences
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                workspace_id:
                  type: integer
                  description: 'The workspace both belong to.'
                  example: 55
                  nullable: false
                audience_id:
                  type: integer
                  description: 'From list-audiences.'
                  example: 44
                  nullable: false
                lead_ids:
                  type: array
                  description: 'Leads to add, from search-leads.'
                  example:
                    - 56789
                  items:
                    type: integer
              required:
                - workspace_id
                - audience_id
                - lead_ids
  /api/external/v1/audiences/remove-leads:
    post:
      summary: 'Remove leads from an audience. The leads themselves are not deleted.'
      operationId: removeLeadsFromAnAudienceTheLeadsThemselvesAreNotDeleted
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  audience_id: 44
                  removed: 1
                  lead_count: 2
                properties:
                  audience_id:
                    type: integer
                    example: 44
                  removed:
                    type: integer
                    example: 1
                  lead_count:
                    type: integer
                    example: 2
      tags:
        - Audiences
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                workspace_id:
                  type: integer
                  description: 'The workspace both belong to.'
                  example: 55
                  nullable: false
                audience_id:
                  type: integer
                  description: 'From list-audiences.'
                  example: 44
                  nullable: false
                lead_ids:
                  type: array
                  description: 'Leads to remove.'
                  example:
                    - 56789
                  items:
                    type: integer
              required:
                - workspace_id
                - audience_id
                - lead_ids
  /api/external/v1/audiences/link-to-campaign:
    post:
      summary: "Link an audience to a campaign, so its leads get that campaign's pages."
      operationId: linkAnAudienceToACampaignSoItsLeadsGetThatCampaignsPages
      description: ''
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  audience_id: 44
                  campaign_id: 123
                  message: 'Audience linked to campaign.'
                properties:
                  audience_id:
                    type: integer
                    example: 44
                  campaign_id:
                    type: integer
                    example: 123
                  message:
                    type: string
                    example: 'Audience linked to campaign.'
      tags:
        - Audiences
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                workspace_id:
                  type: integer
                  description: 'The workspace both belong to.'
                  example: 55
                  nullable: false
                audience_id:
                  type: integer
                  description: 'From list-audiences.'
                  example: 44
                  nullable: false
                campaign_id:
                  type: integer
                  description: 'From campaigns/get-list.'
                  example: 123
                  nullable: false
              required:
                - workspace_id
                - audience_id
                - campaign_id
  /api/external/v1/audiences/unlink-from-campaign:
    post:
      summary: 'Detach an audience from a campaign.'
      operationId: detachAnAudienceFromACampaign
      description: "Removes the link only — the audience, its leads, and any pages already\ngenerated for them are untouched."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  audience_id: 44
                  campaign_id: 123
                  message: 'Audience unlinked from campaign.'
                properties:
                  audience_id:
                    type: integer
                    example: 44
                  campaign_id:
                    type: integer
                    example: 123
                  message:
                    type: string
                    example: 'Audience unlinked from campaign.'
      tags:
        - Audiences
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                workspace_id:
                  type: integer
                  description: 'The workspace both belong to.'
                  example: 55
                  nullable: false
                audience_id:
                  type: integer
                  description: 'From list-audiences.'
                  example: 44
                  nullable: false
                campaign_id:
                  type: integer
                  description: 'From campaigns/get-list.'
                  example: 123
                  nullable: false
              required:
                - workspace_id
                - audience_id
                - campaign_id
  /api/external/v1/audiences/delete:
    post:
      summary: 'Delete an audience. The leads in it are kept.'
      operationId: deleteAnAudienceTheLeadsInItAreKept
      description: "Only the segment is removed. Unlike the dashboard's version, this\nendpoint has no option to delete the leads themselves: that is\nirreversible, and nothing about removing a grouping implies destroying\nthe people in it. Leads that were only reachable through this audience\nremain in the workspace and are still findable with leads/search."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  audience_id: 44
                  leads_kept: 12
                  message: 'Audience deleted. Its leads were kept.'
                properties:
                  audience_id:
                    type: integer
                    example: 44
                  leads_kept:
                    type: integer
                    example: 12
                  message:
                    type: string
                    example: 'Audience deleted. Its leads were kept.'
      tags:
        - Audiences
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                workspace_id:
                  type: integer
                  description: 'The workspace it belongs to.'
                  example: 55
                  nullable: false
                audience_id:
                  type: integer
                  description: 'From list-audiences.'
                  example: 44
                  nullable: false
              required:
                - workspace_id
                - audience_id
  /api/external/v1/generate-api-token:
    post:
      summary: 'Generate an API token. Should be done from the GenPage dashboard.'
      operationId: generateAnAPITokenShouldBeDoneFromTheGenPageDashboard
      description: "This endpoint returns the generated token to be used in the external integration.\nThe token is bound to the workspace it was generated for and cannot be used\nagainst any other workspace. It never expires; delete it to revoke access."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  token: 'sk-proj-<Bearer token>'
                properties:
                  token:
                    type: string
                    example: 'sk-proj-<Bearer token>'
        401:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: Unauthenticated.
                properties:
                  message:
                    type: string
                    example: Unauthenticated.
        403:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'API key generation requires a Scale plan or higher.'
                properties:
                  message:
                    type: string
                    example: 'API key generation requires a Scale plan or higher.'
      tags:
        - Authentication
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: 'A label for the key, shown in the dashboard.'
                  example: 'Zapier production'
                  nullable: false
                workspace_id:
                  type: integer
                  description: 'The workspace the key may act on.'
                  example: 55
                  nullable: false
              required:
                - name
                - workspace_id
  /api/external/v1/get-api-tokens:
    get:
      summary: 'List the API tokens of a workspace.'
      operationId: listTheAPITokensOfAWorkspace
      description: "Returns the workspace's own keys plus any legacy keys that were created\nbefore keys were bound to a workspace (those still work everywhere, so\nhiding them would leave the user unable to find and revoke them)."
      parameters:
        -
          in: query
          name: workspace_id
          description: 'The workspace to list keys for.'
          example: 55
          required: true
          schema:
            type: integer
            description: 'The workspace to list keys for.'
            example: 55
            nullable: false
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  tokens:
                    -
                      id: 9f1c...
                      name: 'Zapier production'
                      created_at: '2026-08-16T10:00:00.000000Z'
                properties:
                  tokens:
                    type: array
                    example:
                      -
                        id: 9f1c...
                        name: 'Zapier production'
                        created_at: '2026-08-16T10:00:00.000000Z'
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          example: 9f1c...
                        name:
                          type: string
                          example: 'Zapier production'
                        created_at:
                          type: string
                          example: '2026-08-16T10:00:00.000000Z'
        401:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: Unauthenticated.
                properties:
                  message:
                    type: string
                    example: Unauthenticated.
      tags:
        - Authentication
  /api/external/v1/delete-api-token:
    delete:
      summary: 'Delete (revoke) an API token.'
      operationId: deleterevokeAnAPIToken
      description: ''
      parameters:
        -
          in: query
          name: token_id
          description: 'The id returned by get-api-tokens.'
          example: 9f1c...
          required: true
          schema:
            type: string
            description: 'The id returned by get-api-tokens.'
            example: 9f1c...
            nullable: false
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'API token deleted successfully'
                properties:
                  message:
                    type: string
                    example: 'API token deleted successfully'
        404:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'API token not found'
                properties:
                  message:
                    type: string
                    example: 'API token not found'
      tags:
        - Authentication
  /api/external/v1/hello-world:
    get:
      summary: 'Test authentication endpoint.'
      operationId: testAuthenticationEndpoint
      description: 'This endpoint is used to test the authentication.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Hello World'
                properties:
                  message:
                    type: string
                    example: 'Hello World'
        401:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: Unauthenticated.
                properties:
                  message:
                    type: string
                    example: Unauthenticated.
      tags:
        - Authentication
  /api/external/v1/hello-world-user:
    get:
      summary: "Test authentication and identify the key's owner."
      operationId: testAuthenticationAndIdentifyTheKeysOwner
      description: "Returns the account the API key belongs to, and the workspace the key is\nbound to (null for keys created before keys were workspace-bound, which\nmay act on every workspace the account can reach)."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Hello World'
                  user:
                    id: 123
                    name: 'John Doe'
                    email: john@example.com
                  workspace_id: 55
                properties:
                  message:
                    type: string
                    example: 'Hello World'
                  user:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 123
                      name:
                        type: string
                        example: 'John Doe'
                      email:
                        type: string
                        example: john@example.com
                  workspace_id:
                    type: integer
                    example: 55
        401:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: Unauthenticated.
                properties:
                  message:
                    type: string
                    example: Unauthenticated.
      tags:
        - Authentication
  /api/external/v1/campaigns/get-list:
    get:
      summary: 'Get the list of campaigns.'
      operationId: getTheListOfCampaigns
      description: 'This endpoint is used to get the list of campaigns.'
      parameters:
        -
          in: query
          name: workspace_id
          description: 'The workspace to list campaigns for.'
          example: 55
          required: true
          schema:
            type: integer
            description: 'The workspace to list campaigns for.'
            example: 55
            nullable: false
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                example:
                  -
                    id: 1
                    name: 'Test Campaign 1'
                    slug: test-campaign-1
                  -
                    id: 2
                    name: 'Saas Outreach'
                    slug: saas-outreach
        401:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: Unauthenticated.
                properties:
                  message:
                    type: string
                    example: Unauthenticated.
        403:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Workspace not found or you do not have permission to access this workspace.'
                properties:
                  message:
                    type: string
                    example: 'Workspace not found or you do not have permission to access this workspace.'
      tags:
        - GenPages
  /api/external/v1/campaigns/create:
    post:
      summary: 'Create a campaign.'
      operationId: createACampaign
      description: "A campaign holds the page template and branding that generated pages use.\nCreate one when an integration needs its own campaign rather than reusing\nan existing one.\n\nThe campaign is created empty — it still needs a page design. Give it\none over the API with `templates/apply` or `pages/generate` (or build\none in the GenPage dashboard) and publish it. Generating pages against\na campaign with no design will produce blank pages, so create-then-generate\nis not a complete flow on its own."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  campaign_id: 231
                  name: 'Enterprise Outreach'
                  slug: enterprise-outreach
                  note: 'The campaign has no page design yet — apply a template (templates/apply) or generate a design (pages/generate) and publish it before generating pages.'
                properties:
                  campaign_id:
                    type: integer
                    example: 231
                  name:
                    type: string
                    example: 'Enterprise Outreach'
                  slug:
                    type: string
                    example: enterprise-outreach
                  note:
                    type: string
                    example: 'The campaign has no page design yet — apply a template (templates/apply) or generate a design (pages/generate) and publish it before generating pages.'
      tags:
        - GenPages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                workspace_id:
                  type: integer
                  description: 'The workspace to create it in.'
                  example: 55
                  nullable: false
                name:
                  type: string
                  description: 'A name. One is generated from the branding if omitted.'
                  example: 'Enterprise Outreach'
                  nullable: true
                branding_id:
                  type: integer
                  description: 'Branding to apply, from the dashboard.'
                  example: 7
                  nullable: true
                prompt:
                  type: string
                  description: 'Used to generate a name when `name` is omitted.'
                  example: 'outbound to fintech CTOs'
                  nullable: true
              required:
                - workspace_id
  /api/external/v1/campaigns/analytics:
    get:
      summary: "Get performance metrics for a workspace's campaigns."
      operationId: getPerformanceMetricsForAWorkspacesCampaigns
      description: "Reports how the generated pages are doing: how many were visited, how\nmany visitors clicked, and how long they stayed.\n\n`visit_percentage` is pages visited as a share of pages generated, so it\nmeasures reach rather than conversion. `click_percentage` is the share of\nunique visitors who clicked something."
      parameters:
        -
          in: query
          name: workspace_id
          description: 'The workspace to report on.'
          example: 55
          required: true
          schema:
            type: integer
            description: 'The workspace to report on.'
            example: 55
            nullable: false
        -
          in: query
          name: campaign_ids
          description: 'Limit to these campaigns. Defaults to all of them.'
          example:
            - 123
            - 124
          required: false
          schema:
            type: array
            description: 'Limit to these campaigns. Defaults to all of them.'
            example:
              - 123
              - 124
            items:
              type: integer
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  campaigns:
                    -
                      campaign_id: 123
                      name: 'Enterprise Outreach'
                      visit_percentage: 42.5
                      click_percentage: 18.2
                      average_time_on_page_seconds: 47
                      pages_visited: 85
                      unique_visitors: 71
                      total_button_clicks: 19
                properties:
                  campaigns:
                    type: array
                    example:
                      -
                        campaign_id: 123
                        name: 'Enterprise Outreach'
                        visit_percentage: 42.5
                        click_percentage: 18.2
                        average_time_on_page_seconds: 47
                        pages_visited: 85
                        unique_visitors: 71
                        total_button_clicks: 19
                    items:
                      type: object
                      properties:
                        campaign_id:
                          type: integer
                          example: 123
                        name:
                          type: string
                          example: 'Enterprise Outreach'
                        visit_percentage:
                          type: number
                          example: 42.5
                        click_percentage:
                          type: number
                          example: 18.2
                        average_time_on_page_seconds:
                          type: integer
                          example: 47
                        pages_visited:
                          type: integer
                          example: 85
                        unique_visitors:
                          type: integer
                          example: 71
                        total_button_clicks:
                          type: integer
                          example: 19
      tags:
        - GenPages
  /api/external/v1/brandings/get-list:
    get:
      summary: 'List the brandings in a workspace.'
      operationId: listTheBrandingsInAWorkspace
      description: "A branding is the visual identity a campaign renders with — logo,\ncolours, fonts. Call this to resolve a `branding_id` for\ncampaigns/create; brandings themselves are built in the dashboard."
      parameters:
        -
          in: query
          name: workspace_id
          description: 'The workspace to list for.'
          example: 55
          required: true
          schema:
            type: integer
            description: 'The workspace to list for.'
            example: 55
            nullable: false
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                example:
                  -
                    branding_id: 7
                    name: 'Acme Corp'
                    is_default: true
      tags:
        - GenPages
  /api/external/v1/pages/design:
    get:
      summary: "Get a campaign's current page design."
      operationId: getACampaignsCurrentPageDesign
      description: "Returns the HTML and CSS the campaign renders. Every generated page is\nthis design with the lead's variables substituted in, so this is what to\nread to see what the pages actually say."
      parameters:
        -
          in: query
          name: workspace_id
          description: 'The workspace the campaign belongs to.'
          example: 55
          required: true
          schema:
            type: integer
            description: 'The workspace the campaign belongs to.'
            example: 55
            nullable: false
        -
          in: query
          name: campaign_id
          description: 'From campaigns/get-list.'
          example: 231
          required: true
          schema:
            type: integer
            description: 'From campaigns/get-list.'
            example: 231
            nullable: false
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                oneOf:
                  -
                    description: 'has a design'
                    type: object
                    example:
                      campaign_id: 231
                      has_design: true
                      is_live: true
                      has_unpublished_changes: false
                      html: '<section>…</section>'
                      css: 'body{…}'
                      updated_at: '2026-08-17T09:00:00.000000Z'
                      note: null
                    properties:
                      campaign_id:
                        type: integer
                        example: 231
                      has_design:
                        type: boolean
                        example: true
                      is_live:
                        type: boolean
                        example: true
                      has_unpublished_changes:
                        type: boolean
                        example: false
                      html:
                        type: string
                        example: '<section>…</section>'
                      css:
                        type: string
                        example: 'body{…}'
                      updated_at:
                        type: string
                        example: '2026-08-17T09:00:00.000000Z'
                      note:
                        type: string
                        example: null
                  -
                    description: 'no design yet'
                    type: object
                    example:
                      campaign_id: 231
                      has_design: false
                      is_live: false
                      html: null
                      css: null
                      note: 'This campaign has no design yet. Apply a template or generate one.'
                    properties:
                      campaign_id:
                        type: integer
                        example: 231
                      has_design:
                        type: boolean
                        example: false
                      is_live:
                        type: boolean
                        example: false
                      html:
                        type: string
                        example: null
                      css:
                        type: string
                        example: null
                      note:
                        type: string
                        example: 'This campaign has no design yet. Apply a template or generate one.'
      tags:
        - GenPages
  /api/external/v1/pages/generate:
    post:
      summary: "Ask the AI builder to design a campaign's page. Returns a run id."
      operationId: askTheAIBuilderToDesignACampaignsPageReturnsARunId
      description: "The builder writes its result straight onto the campaign, so once the run\nfinishes, pages/design returns the new HTML and newly generated pages use\nit. Generation spends credits; with none left the request fails with 402.\n\nBy default the builder edits the campaign's existing design. Pass\n`replace: true` to have it start from a blank page instead."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  run_id: run_01H…
                  status: queued
                  campaign_id: 231
                properties:
                  run_id:
                    type: string
                    example: run_01H…
                  status:
                    type: string
                    example: queued
                  campaign_id:
                    type: integer
                    example: 231
        402:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'No credits remaining'
                properties:
                  message:
                    type: string
                    example: 'No credits remaining'
      tags:
        - GenPages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                workspace_id:
                  type: integer
                  description: 'The workspace the campaign belongs to.'
                  example: 55
                  nullable: false
                campaign_id:
                  type: integer
                  description: 'The campaign to design.'
                  example: 231
                  nullable: false
                prompt:
                  type: string
                  description: 'What to build or change.'
                  example: 'A landing page for fintech CTOs, with a hero, three benefits, and a demo CTA.'
                  nullable: false
                replace:
                  type: boolean
                  description: 'Start from a blank page instead of editing the current design.'
                  example: false
                  nullable: true
              required:
                - workspace_id
                - campaign_id
                - prompt
  /api/external/v1/pages/generate/status:
    get:
      summary: "Check a design run's progress."
      operationId: checkADesignRunsProgress
      description: "`status` is one of `queued`, `running`, `success`, `error`, `cancelled`.\nOn `success`, read the result with pages/design."
      parameters:
        -
          in: query
          name: workspace_id
          description: 'The workspace the run belongs to.'
          example: 55
          required: true
          schema:
            type: integer
            description: 'The workspace the run belongs to.'
            example: 55
            nullable: false
        -
          in: query
          name: run_id
          description: 'From pages/generate.'
          example: run_01H…
          required: true
          schema:
            type: string
            description: 'From pages/generate.'
            example: run_01H…
            nullable: false
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  run_id: run_01H…
                  status: running
                  campaign_id: 231
                  error: null
                properties:
                  run_id:
                    type: string
                    example: run_01H…
                  status:
                    type: string
                    example: running
                  campaign_id:
                    type: integer
                    example: 231
                  error:
                    type: string
                    example: null
      tags:
        - GenPages
  /api/external/v1/pages/publish:
    post:
      summary: "Publish a campaign's design, putting it live."
      operationId: publishACampaignsDesignPuttingItLive
      description: "A design is edited as a draft. Visitors are served the *published*\nsnapshot, so a campaign whose design has never been published shows a\n\"not live yet\" page to anyone who opens a generated link. This copies the\ncurrent draft over the published snapshot.\n\nPublishing replaces what is currently live, and takes effect immediately\nfor every page in the campaign — including ones generated earlier."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  campaign_id: 231
                  is_live: true
                  published_at: '2026-08-17T09:00:00.000000Z'
                  message: 'Design published. Pages in this campaign are now live.'
                properties:
                  campaign_id:
                    type: integer
                    example: 231
                  is_live:
                    type: boolean
                    example: true
                  published_at:
                    type: string
                    example: '2026-08-17T09:00:00.000000Z'
                  message:
                    type: string
                    example: 'Design published. Pages in this campaign are now live.'
        409:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'This campaign has no design to publish. Apply a template or generate one first.'
                properties:
                  message:
                    type: string
                    example: 'This campaign has no design to publish. Apply a template or generate one first.'
      tags:
        - GenPages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                workspace_id:
                  type: integer
                  description: 'The workspace the campaign belongs to.'
                  example: 55
                  nullable: false
                campaign_id:
                  type: integer
                  description: 'The campaign to publish.'
                  example: 231
                  nullable: false
              required:
                - workspace_id
                - campaign_id
  /api/external/v1/pages/unpublish:
    post:
      summary: "Take a campaign's pages offline."
      operationId: takeACampaignsPagesOffline
      description: "Clears the published snapshot. Every generated link in the campaign then\nshows a \"not live yet\" page. The design itself is untouched — it stays as\na draft and can be published again."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  campaign_id: 231
                  is_live: false
                  message: 'Pages in this campaign are no longer live. The design is kept as a draft.'
                properties:
                  campaign_id:
                    type: integer
                    example: 231
                  is_live:
                    type: boolean
                    example: false
                  message:
                    type: string
                    example: 'Pages in this campaign are no longer live. The design is kept as a draft.'
      tags:
        - GenPages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                workspace_id:
                  type: integer
                  description: 'The workspace the campaign belongs to.'
                  example: 55
                  nullable: false
                campaign_id:
                  type: integer
                  description: 'The campaign to take offline.'
                  example: 231
                  nullable: false
              required:
                - workspace_id
                - campaign_id
  /api/external/v1/templates/get-list:
    get:
      summary: 'List the page templates available to a workspace.'
      operationId: listThePageTemplatesAvailableToAWorkspace
      description: "Two kinds come back. `workspace` templates were built by this account in\nthe GenPage dashboard; `premade` ones ship with GenPage and are available\nto everyone. Either can be applied to a campaign."
      parameters:
        -
          in: query
          name: workspace_id
          description: 'The workspace to list for.'
          example: 55
          required: true
          schema:
            type: integer
            description: 'The workspace to list for.'
            example: 55
            nullable: false
        -
          in: query
          name: search
          description: 'Match on template name.'
          example: saas
          required: false
          schema:
            type: string
            description: 'Match on template name.'
            example: saas
            nullable: true
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                example:
                  -
                    template_id: 88
                    name: 'SaaS outbound'
                    description: 'Hero, social proof, single CTA'
                    source: workspace
                  -
                    template_id: 12
                    name: 'Minimal landing'
                    description: null
                    source: premade
      tags:
        - GenPages
  /api/external/v1/templates/apply:
    post:
      summary: "Apply a template's design to a campaign."
      operationId: applyATemplatesDesignToACampaign
      description: "Copies the page design onto the campaign, replacing whatever design it\nhad. Use it right after creating a campaign — until a campaign has a\ndesign, the pages generated for it are blank.\n\nThis overwrites: a campaign that already has a design loses it, and pages\ngenerated afterwards use the new one. Pages already generated keep what\nthey were built with until they are regenerated."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                oneOf:
                  -
                    description: 'campaign was not live'
                    type: object
                    example:
                      campaign_id: 231
                      template_id: 88
                      is_live: false
                      message: "Template applied. Publish the design to make this campaign's pages live."
                    properties:
                      campaign_id:
                        type: integer
                        example: 231
                      template_id:
                        type: integer
                        example: 88
                      is_live:
                        type: boolean
                        example: false
                      message:
                        type: string
                        example: "Template applied. Publish the design to make this campaign's pages live."
                  -
                    description: 'campaign already live'
                    type: object
                    example:
                      campaign_id: 231
                      template_id: 88
                      is_live: true
                      message: 'Template applied as a draft. The campaign is still serving its previously published design — publish to switch pages over to this one.'
                    properties:
                      campaign_id:
                        type: integer
                        example: 231
                      template_id:
                        type: integer
                        example: 88
                      is_live:
                        type: boolean
                        example: true
                      message:
                        type: string
                        example: 'Template applied as a draft. The campaign is still serving its previously published design — publish to switch pages over to this one.'
        404:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Template not found'
                properties:
                  message:
                    type: string
                    example: 'Template not found'
      tags:
        - GenPages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                workspace_id:
                  type: integer
                  description: 'The workspace the campaign belongs to.'
                  example: 55
                  nullable: false
                campaign_id:
                  type: integer
                  description: 'From campaigns/get-list or campaigns/create.'
                  example: 231
                  nullable: false
                template_id:
                  type: integer
                  description: 'From templates/get-list.'
                  example: 88
                  nullable: false
              required:
                - workspace_id
                - campaign_id
                - template_id
  /api/external/v1/zapier/get-leads-from-job:
    get:
      summary: 'Get the leads that were upserted by a job.'
      operationId: getTheLeadsThatWereUpsertedByAJob
      description: 'This endpoint is used to get the leads that were upserted by a job.'
      parameters:
        -
          in: query
          name: job_id
          description: 'The job id returned by an upsert endpoint.'
          example: 9f1c8b2e-...
          required: true
          schema:
            type: string
            description: 'The job id returned by an upsert endpoint.'
            example: 9f1c8b2e-...
            nullable: false
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                example:
                  -
                    lead_id: 56789
                    genpage_url: 'https://myworkspace.genpa.ge/aws-john'
                    name: 'John Doe'
                    email: john@aws.com
                    company_name: AWS
        401:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: Unauthenticated.
                properties:
                  message:
                    type: string
                    example: Unauthenticated.
        404:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  status: NOT_FOUND
                properties:
                  status:
                    type: string
                    example: NOT_FOUND
        503:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  status: NO_LEADS
                  message: 'No leads have been processed for this job yet. Try again later.'
                properties:
                  status:
                    type: string
                    example: NO_LEADS
                  message:
                    type: string
                    example: 'No leads have been processed for this job yet. Try again later.'
      tags:
        - Leads
  /api/external/v1/leads/search:
    get:
      summary: 'Search the leads in a workspace.'
      operationId: searchTheLeadsInAWorkspace
      description: "Free-text search across name, email, and company, narrowed by campaign,\naudience, or how the lead has engaged with its page."
      parameters:
        -
          in: query
          name: workspace_id
          description: 'The workspace to search.'
          example: 55
          required: true
          schema:
            type: integer
            description: 'The workspace to search.'
            example: 55
            nullable: false
        -
          in: query
          name: search
          description: 'Matches name, email, or company.'
          example: acme
          required: false
          schema:
            type: string
            description: 'Matches name, email, or company.'
            example: acme
            nullable: true
        -
          in: query
          name: campaign_ids
          description: 'Only leads on these campaigns.'
          example:
            - 1
            - 2
          required: false
          schema:
            type: array
            description: 'Only leads on these campaigns.'
            example:
              - 1
              - 2
            items:
              type: integer
        -
          in: query
          name: audience_ids
          description: 'Only leads in these audiences.'
          example:
            - 3
          required: false
          schema:
            type: array
            description: 'Only leads in these audiences.'
            example:
              - 3
            items:
              type: integer
        -
          in: query
          name: engagement
          description: 'Filter by engagement: all, page_viewed, button_clicked, scroll_100_percent, form_submitted.'
          example:
            - form_submitted
          required: false
          schema:
            type: array
            description: 'Filter by engagement: all, page_viewed, button_clicked, scroll_100_percent, form_submitted.'
            example:
              - form_submitted
            items:
              type: string
        -
          in: query
          name: limit
          description: 'How many to return, 1-100. Defaults to 25.'
          example: 25
          required: false
          schema:
            type: integer
            description: 'How many to return, 1-100. Defaults to 25.'
            example: 25
            nullable: true
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  total: 340
                  returned: 25
                  leads:
                    -
                      lead_id: 56789
                      name: 'John Doe'
                      email: john@aws.com
                      company_name: AWS
                      company_domain: aws.com
                      genpage_url: 'https://myworkspace.genpa.ge/aws-john'
                      created_at: '2026-08-16T10:00:00.000000Z'
                properties:
                  total:
                    type: integer
                    example: 340
                  returned:
                    type: integer
                    example: 25
                  leads:
                    type: array
                    example:
                      -
                        lead_id: 56789
                        name: 'John Doe'
                        email: john@aws.com
                        company_name: AWS
                        company_domain: aws.com
                        genpage_url: 'https://myworkspace.genpa.ge/aws-john'
                        created_at: '2026-08-16T10:00:00.000000Z'
                    items:
                      type: object
                      properties:
                        lead_id:
                          type: integer
                          example: 56789
                        name:
                          type: string
                          example: 'John Doe'
                        email:
                          type: string
                          example: john@aws.com
                        company_name:
                          type: string
                          example: AWS
                        company_domain:
                          type: string
                          example: aws.com
                        genpage_url:
                          type: string
                          example: 'https://myworkspace.genpa.ge/aws-john'
                        created_at:
                          type: string
                          example: '2026-08-16T10:00:00.000000Z'
      tags:
        - Leads
  /api/external/v1/leads/get:
    get:
      summary: 'Get one lead, with every field and its enrichment state.'
      operationId: getOneLeadWithEveryFieldAndItsEnrichmentState
      description: ''
      parameters:
        -
          in: query
          name: lead_id
          description: 'From search-leads or an upsert job.'
          example: 56789
          required: true
          schema:
            type: integer
            description: 'From search-leads or an upsert job.'
            example: 56789
            nullable: false
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  lead_id: 56789
                  name: 'John Doe'
                  email: john@aws.com
                  company_name: AWS
                  company_domain: aws.com
                  genpage_url: 'https://myworkspace.genpa.ge/aws-john'
                  variables:
                    linkedin_profile_url: 'https://...'
                    pain_point: ...
                  audiences:
                    -
                      id: 3
                      name: Enterprise
                  pending_enrichments:
                    - company_domain
                  created_at: '2026-08-16T10:00:00.000000Z'
                properties:
                  lead_id:
                    type: integer
                    example: 56789
                  name:
                    type: string
                    example: 'John Doe'
                  email:
                    type: string
                    example: john@aws.com
                  company_name:
                    type: string
                    example: AWS
                  company_domain:
                    type: string
                    example: aws.com
                  genpage_url:
                    type: string
                    example: 'https://myworkspace.genpa.ge/aws-john'
                  variables:
                    type: object
                    properties:
                      linkedin_profile_url:
                        type: string
                        example: 'https://...'
                      pain_point:
                        type: string
                        example: ...
                  audiences:
                    type: array
                    example:
                      -
                        id: 3
                        name: Enterprise
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                          example: 3
                        name:
                          type: string
                          example: Enterprise
                  pending_enrichments:
                    type: array
                    example:
                      - company_domain
                    items:
                      type: string
                  created_at:
                    type: string
                    example: '2026-08-16T10:00:00.000000Z'
        404:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Lead not found'
                properties:
                  message:
                    type: string
                    example: 'Lead not found'
      tags:
        - Leads
  /api/external/v1/leads/enrich:
    post:
      summary: 'Enrich existing leads, spending credits to research them.'
      operationId: enrichExistingLeadsSpendingCreditsToResearchThem
      description: "Each type is a separate piece of research, and each costs credits per\nlead. Ask for only what the pages actually use.\n\n- `linkedin_profile_url` — scrape the lead's LinkedIn profile\n- `company_domain` — AI analysis of the company\n- `person_analysis` — AI analysis of the person\n- `linkedin_posts_person` — the person's recent posts\n- `linkedin_posts_company` — the company page's recent posts\n\nA lead missing the inputs a type needs (no LinkedIn URL, no domain) is\nskipped rather than failing the batch — compare `leads_to_enrich` against\nwhat you sent, and check `skipped_leads`. Results land on the leads\nthemselves; poll `job_id` with get-status, then read them back with\nget-lead."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  job_id: 9f1c8b2e-...
                  message: 'Enrichment job started'
                  leads_to_enrich: 2
                  skipped_leads: 0
                properties:
                  job_id:
                    type: string
                    example: 9f1c8b2e-...
                  message:
                    type: string
                    example: 'Enrichment job started'
                  leads_to_enrich:
                    type: integer
                    example: 2
                  skipped_leads:
                    type: integer
                    example: 0
        400:
          description: ''
          content:
            application/json:
              schema:
                oneOf:
                  -
                    description: 'no valid lead ids'
                    type: object
                    example:
                      message: 'No valid leads found for the given IDs.'
                    properties:
                      message:
                        type: string
                        example: 'No valid leads found for the given IDs.'
                  -
                    description: 'every lead skipped'
                    type: object
                    example:
                      message: 'No leads have the required fields for enrichment. LinkedIn Profile requires linkedin_profile_url, Company Research requires a company name, domain, or LinkedIn profile, Prospect Research requires a name or LinkedIn profile, LinkedIn Posts require a profile or company page.'
                      skipped_leads:
                        -
                          lead_id: 56790
                          reason: 'Missing required fields for enrichment'
                    properties:
                      message:
                        type: string
                        example: 'No leads have the required fields for enrichment. LinkedIn Profile requires linkedin_profile_url, Company Research requires a company name, domain, or LinkedIn profile, Prospect Research requires a name or LinkedIn profile, LinkedIn Posts require a profile or company page.'
                      skipped_leads:
                        type: array
                        example:
                          -
                            lead_id: 56790
                            reason: 'Missing required fields for enrichment'
                        items:
                          type: object
                          properties:
                            lead_id:
                              type: integer
                              example: 56790
                            reason:
                              type: string
                              example: 'Missing required fields for enrichment'
      tags:
        - Leads
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                workspace_id:
                  type: integer
                  description: 'The workspace the leads belong to.'
                  example: 55
                  nullable: false
                lead_ids:
                  type: array
                  description: 'Leads to enrich, from search-leads.'
                  example:
                    - 56789
                    - 56790
                  items:
                    type: integer
                enrichment_types:
                  type: array
                  description: 'One or more of linkedin_profile_url, company_domain, person_analysis, linkedin_posts_person, linkedin_posts_company.'
                  example:
                    - company_domain
                  items:
                    type: string
              required:
                - workspace_id
                - lead_ids
                - enrichment_types
  /api/external/v1/leads/upsert-leads:
    post:
      summary: 'Upsert leads.'
      operationId: upsertLeads
      description: "This endpoint is used to upsert (update or insert) leads.\n\nThe leads are sent in the request body.\nThe leads are an array of objects.\nThe leads.*.values are key/value pairs with the values of the lead.\n\n---\n### Required fields for creating or updating a lead\n\n**To create a new lead, at least one of:**\n- `email`\n- `linkedin_profile_url`\n\n**To update an existing lead, at least one of:**\n- `lead_id` (GenPage Lead ID)\n- `genpage_url` (GenPage URL)\n\n---\n### Optional but strongly recommended fields\n- `first_name`\n- `company_name`\n- `company_domain`\n---\n\nThe response is the job ID.\n\nThe job ID can be used to get the status of the job, and get all the leads that were upserted by this request."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  job_id: 9f1c8b2e-...
                properties:
                  job_id:
                    type: string
                    example: 9f1c8b2e-...
        401:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: Unauthenticated.
                properties:
                  message:
                    type: string
                    example: Unauthenticated.
      tags:
        - Leads
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                from:
                  type: string
                  description: 'The service that is sending the leads, use your own company/service name please. Defaults to NOT_SPECIFIED.'
                  example: MyCompanyName
                  nullable: true
                campaign_id:
                  type: integer
                  description: 'The campaign ID to add the leads to.'
                  example: 1
                  nullable: false
                audience_id:
                  type: integer
                  description: 'The audience ID to add the leads to.'
                  example: 1
                  nullable: true
                callback_url:
                  type: string
                  description: 'Optional callback URL.'
                  example: 'https://example.com/callback'
                  nullable: true
                send_email:
                  type: boolean
                  description: 'Send the configured email for each upserted lead. Defaults to false.'
                  example: false
                  nullable: true
                is_generate_ai_analysis:
                  type: boolean
                  description: 'Whether to generate AI analysis for the leads.'
                  example: true
                  nullable: true
                enrich_data:
                  type: boolean
                  description: 'Enrich the leads from their email/domain.'
                  example: false
                  nullable: true
                generate_ai_variables:
                  type: boolean
                  description: 'Generate AI variable values for the leads. Defaults to false.'
                  example: false
                  nullable: true
                leads:
                  type: array
                  description: 'Array of lead objects to upsert.'
                  example:
                    -
                      lead_id: 16
                      genpage_url: 'https://myworkspace.genpa.ge/aws-john'
                      values:
                        first_name: John
                        email: john@aws.com
                        company_name: 'Amazon Web Services'
                        linkedin_profile_url: 'https://www.linkedin.com/in/john-doe-1234567890'
                  items:
                    type: object
                    properties:
                      lead_id:
                        type: integer
                        description: 'The GenPage Lead ID for updating existing leads.'
                        example: 16
                        nullable: true
                      genpage_url:
                        type: string
                        description: 'The GenPage URL for updating existing leads.'
                        example: 'https://myworkspace.genpa.ge/aws-john'
                        nullable: true
                      values:
                        type: object
                        description: 'Object containing key/value pairs with the lead data. You can send any key/value (value can be a string or a number) pairs that you want to add to the lead.'
                        example:
                          first_name: John
                          email: john@aws.com
                          company_name: 'Amazon Web Services'
                          linkedin_profile_url: 'https://www.linkedin.com/in/john-doe-1234567890'
                        nullable: true
                        properties:
                          first_name:
                            type: string
                            description: 'The first name of the lead.'
                            example: John
                            nullable: false
                          last_name:
                            type: string
                            description: 'The last name of the lead.'
                            example: Doe
                            nullable: false
                          email:
                            type: string
                            description: 'The email address of the lead.'
                            example: john@aws.com
                            nullable: false
                          company_name:
                            type: string
                            description: 'The company name of the lead.'
                            example: 'Amazon Web Services'
                            nullable: false
                          linkedin_profile_url:
                            type: string
                            description: 'The LinkedIn profile URL of the lead.'
                            example: 'https://www.linkedin.com/in/john-doe-1234567890'
                            nullable: false
                          company_domain:
                            type: string
                            description: 'The company domain of the lead.'
                            example: amazon.com
                            nullable: false
                          my_custom_variable:
                            type: string
                            description: 'Custom variable for the lead.'
                            example: 'My custom value'
                            nullable: false
                    required:
                      - values
              required:
                - campaign_id
                - leads
  /api/external/v1/leads/upsert-lead:
    post:
      summary: 'Upsert (update or create) a single lead.'
      operationId: upsertupdateOrCreateASingleLead
      description: "This endpoint is used to upsert a single lead.\n\nThe \"values\" object requires at least one of the following fields, otherwise it will throw an error:\n- first_name\n- email\n- company_name\n- company_domain\n- linkedin_profile_url"
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  job_id: 9f1c8b2e-...
                properties:
                  job_id:
                    type: string
                    example: 9f1c8b2e-...
        400:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Missing required fields: first_name, email, company_name, company_domain, or linkedin_profile_url.'
                properties:
                  message:
                    type: string
                    example: 'Missing required fields: first_name, email, company_name, company_domain, or linkedin_profile_url.'
        401:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: Unauthenticated.
                properties:
                  message:
                    type: string
                    example: Unauthenticated.
        404:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Campaign not found'
                properties:
                  message:
                    type: string
                    example: 'Campaign not found'
      tags:
        - Leads
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                from:
                  type: string
                  description: 'The service that is sending the lead, use your own company/service name please. Defaults to NOT_SPECIFIED.'
                  example: MyCompanyName
                  nullable: true
                campaign_id:
                  type: integer
                  description: 'The campaign ID to add the lead to.'
                  example: 1
                  nullable: false
                audience_id:
                  type: integer
                  description: 'An audience to add the lead to.'
                  example: 1
                  nullable: true
                callback_url:
                  type: string
                  description: 'Optional callback URL.'
                  example: 'https://example.com/callback'
                  nullable: true
                send_email:
                  type: boolean
                  description: 'Send the configured email for the upserted lead. Defaults to false.'
                  example: false
                  nullable: true
                is_generate_ai_analysis:
                  type: boolean
                  description: 'Whether to generate AI analysis for the lead.'
                  example: true
                  nullable: true
                enrich_data:
                  type: boolean
                  description: 'Enrich the lead from their email/domain.'
                  example: false
                  nullable: true
                generate_ai_variables:
                  type: boolean
                  description: 'Generate AI variable values for the lead. Defaults to false.'
                  example: false
                  nullable: true
                lead_id:
                  type: integer
                  description: 'The GenPage Lead ID for updating existing leads.'
                  example: 16
                  nullable: true
                genpage_url:
                  type: string
                  description: 'The GenPage URL for updating existing leads.'
                  example: 'https://myworkspace.genpa.ge/aws-john'
                  nullable: true
                values:
                  type: object
                  description: 'Object containing key/value pairs with the lead data. You can send any key/value (value can be a string or a number) pairs that you want to add to the lead.'
                  example:
                    first_name: John
                    email: john@aws.com
                    company_name: 'Amazon Web Services'
                    linkedin_profile_url: 'https://www.linkedin.com/in/john-doe-1234567890'
                  nullable: true
                  properties: {  }
              required:
                - campaign_id
                - values
  /api/external/v1/leads/import-to-workspace:
    post:
      summary: 'Import leads into a workspace, without a campaign.'
      operationId: importLeadsIntoAWorkspaceWithoutACampaign
      description: "Use this when the leads are not tied to a landing page yet; link them to\ncampaigns later through an audience.\n\nThe response depends on how the import ran. Queued imports (the default,\nand always the case when any enrichment or campaign is requested) answer\nwith a `job_id` to poll on `/leads/get-status`. Immediate imports\n(`sync: true` with no enrichment and no campaigns) answer with the result\ndirectly and carry a `job_id` of null."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                oneOf:
                  -
                    description: ''
                    type: object
                    example:
                      job_id: 9f1c8b2e-...
                    properties:
                      job_id:
                        type: string
                        example: 9f1c8b2e-...
                  -
                    description: ''
                    type: object
                    example:
                      job_id: null
                      success: true
                      imported_count: 2
                      duplicate_count: 1
                      lead_ids:
                        - 56789
                        - 56790
                      errors: []
                    properties:
                      job_id:
                        type: string
                        example: null
                      success:
                        type: boolean
                        example: true
                      imported_count:
                        type: integer
                        example: 2
                      duplicate_count:
                        type: integer
                        example: 1
                      lead_ids:
                        type: array
                        example:
                          - 56789
                          - 56790
                        items:
                          type: integer
                      errors:
                        type: array
                        example: []
        403:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Workspace not found or you do not have permission to access this workspace.'
                properties:
                  message:
                    type: string
                    example: 'Workspace not found or you do not have permission to access this workspace.'
      tags:
        - Leads
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                workspace_id:
                  type: integer
                  description: 'The workspace to import into.'
                  example: 55
                  nullable: false
                leads:
                  type: array
                  description: 'Array of lead objects.'
                  example:
                    -
                      values:
                        first_name: John
                        email: john@aws.com
                        company_name: 'Amazon Web Services'
                  items:
                    type: object
                    properties:
                      values:
                        type: object
                        description: 'Key/value pairs with the lead data.'
                        example:
                          first_name: John
                          email: john@aws.com
                        nullable: false
                        properties: {  }
                    required:
                      - values
                from:
                  type: string
                  description: 'The service sending the leads.'
                  example: MyCompanyName
                  nullable: true
                send_email:
                  type: boolean
                  description: 'Send the configured email for each imported lead. Defaults to false.'
                  example: false
                  nullable: true
                is_generate_ai_analysis:
                  type: boolean
                  description: 'Generate the AI company analysis.'
                  example: false
                  nullable: true
                is_generate_person_analysis:
                  type: boolean
                  description: 'Generate the AI person analysis.'
                  example: false
                  nullable: true
                is_scrape_person_posts:
                  type: boolean
                  description: "Scrape the lead's recent LinkedIn posts."
                  example: false
                  nullable: true
                is_scrape_company_posts:
                  type: boolean
                  description: "Scrape the company page's recent LinkedIn posts."
                  example: false
                  nullable: true
                enrich_data:
                  type: boolean
                  description: 'Enrich the leads from their email/domain.'
                  example: false
                  nullable: true
                audience_id:
                  type: integer
                  description: 'An audience to add the imported leads to.'
                  example: 3
                  nullable: true
                sync:
                  type: boolean
                  description: 'Import immediately instead of queueing, when no enrichment is requested.'
                  example: false
                  nullable: true
                campaign_ids:
                  type: array
                  description: 'Campaigns to attach the leads to.'
                  example:
                    - 1
                    - 2
                  items:
                    type: integer
                generate_ai_variables:
                  type: boolean
                  description: 'Generate AI variable values.'
                  example: false
                  nullable: true
                trigger_audience_summary:
                  type: boolean
                  description: 'Trigger the audience summary generation after the import.'
                  example: false
                  nullable: true
              required:
                - workspace_id
                - leads
  /api/external/v1/leads/get-status:
    get:
      summary: 'Get the status of the job.'
      operationId: getTheStatusOfTheJob
      description: "This endpoint is used to get the status of the job.\nOnce the job is completed, the status will be \"completed\".\n\nThe status can be:\n- pending\n- processing\n- step_linkedin\n- step_import\n- completed\n- error\n\nOnce the job is completed, please use the getLeads endpoint to get all the leads that were upserted by this request."
      parameters:
        -
          in: query
          name: job_id
          description: 'The job id returned by an upsert endpoint.'
          example: 9f1c8b2e-...
          required: true
          schema:
            type: string
            description: 'The job id returned by an upsert endpoint.'
            example: 9f1c8b2e-...
            nullable: false
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  status: pending
                  processed_rows: 10
                  total_rows: 100
                properties:
                  status:
                    type: string
                    example: pending
                  processed_rows:
                    type: integer
                    example: 10
                  total_rows:
                    type: integer
                    example: 100
        401:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: Unauthenticated.
                properties:
                  message:
                    type: string
                    example: Unauthenticated.
        404:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  status: not_found
                properties:
                  status:
                    type: string
                    example: not_found
      tags:
        - Leads
  /api/external/v1/leads/get-leads:
    get:
      summary: 'Get the leads that were upserted by a job.'
      operationId: getTheLeadsThatWereUpsertedByAJob
      description: 'This endpoint is used to get the leads that were upserted by a job.'
      parameters:
        -
          in: query
          name: job_id
          description: 'The job id returned by an upsert endpoint.'
          example: 9f1c8b2e-...
          required: true
          schema:
            type: string
            description: 'The job id returned by an upsert endpoint.'
            example: 9f1c8b2e-...
            nullable: false
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                example:
                  -
                    lead_id: 56789
                    genpage_url: 'https://myworkspace.genpa.ge/aws-john'
                    name: 'John Doe'
                    email: john@aws.com
                    company_name: AWS
        401:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: Unauthenticated.
                properties:
                  message:
                    type: string
                    example: Unauthenticated.
        404:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  status: NOT_FOUND
                properties:
                  status:
                    type: string
                    example: NOT_FOUND
        503:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  status: NO_LEADS
                  message: 'No leads have been processed for this job yet. Try again later.'
                properties:
                  status:
                    type: string
                    example: NO_LEADS
                  message:
                    type: string
                    example: 'No leads have been processed for this job yet. Try again later.'
      tags:
        - Leads
  /api/external/v1/workspaces/get-list:
    get:
      summary: 'Get the list of workspaces.'
      operationId: getTheListOfWorkspaces
      description: 'This endpoint is used to get the list of workspaces the user has access to.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                example:
                  -
                    id: 1
                    name: 'My Company Name'
                    slug: my-company-name
                  -
                    id: 2
                    name: 'SAAS Outreach'
                    slug: saas-outreach
        401:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: Unauthenticated.
                properties:
                  message:
                    type: string
                    example: Unauthenticated.
      tags:
        - Workspaces
  /api/external/v1/workspaces/get-variable-list:
    get:
      summary: 'Get the list of variables (or columns) for a workspace.'
      operationId: getTheListOfVariablesorColumnsForAWorkspace
      description: "This endpoint retrieves all available variables/columns for a specific workspace.\nIt returns both default variables (first_name, email, company_name, company_domain)\nand any custom variables that have been created for the workspace.\n\nWhen updating or inserting a lead, you can use the variables/columns from this endpoint\nto add the values to the specific variable/column for the lead."
      parameters:
        -
          in: query
          name: workspace_id
          description: 'The workspace to list the variables of.'
          example: 55
          required: true
          schema:
            type: integer
            description: 'The workspace to list the variables of.'
            example: 55
            nullable: false
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                example:
                  -
                    key: linkedin_profile_url
                    helpText: 'LinkedIn profile URL (at least one of LinkedIn URL, Company Domain, or Email is required)'
                  -
                    key: email
                    helpText: 'Email address (at least one of LinkedIn URL, Company Domain, or Email is required)'
                  -
                    key: company_domain
                    helpText: 'Company domain (at least one of LinkedIn URL, Company Domain, or Email is required)'
                  -
                    key: first_name
                    helpText: 'First name'
                  -
                    key: company_name
                    helpText: 'Company name'
                  -
                    key: 'My Custom Variable1'
                  -
                    key: custom_variable2
        401:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: Unauthenticated.
                properties:
                  message:
                    type: string
                    example: Unauthenticated.
        422:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'The given data was invalid.'
                  errors:
                    workspace_id:
                      - 'The workspace id field is required.'
                properties:
                  message:
                    type: string
                    example: 'The given data was invalid.'
                  errors:
                    type: object
                    properties:
                      workspace_id:
                        type: array
                        example:
                          - 'The workspace id field is required.'
                        items:
                          type: string
      tags:
        - Workspaces
  /api/external/v1/zapier/test:
    get:
      summary: 'Test authentication endpoint.'
      operationId: testAuthenticationEndpoint
      description: 'This endpoint is used to test the authentication.'
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Hello World'
                  user:
                    id: 123
                    name: 'John Doe'
                    email: john@example.com
                properties:
                  message:
                    type: string
                    example: 'Hello World'
                  user:
                    type: object
                    properties:
                      id:
                        type: integer
                        example: 123
                      name:
                        type: string
                        example: 'John Doe'
                      email:
                        type: string
                        example: john@example.com
        401:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: Unauthenticated.
                properties:
                  message:
                    type: string
                    example: Unauthenticated.
      tags:
        - Zapier
  /api/external/v1/zapier/upsert-lead:
    post:
      summary: 'Create a lead through Zapier.'
      operationId: createALeadThroughZapier
      description: "Set `is_test` to true to have the endpoint answer with a sample page URL\nwithout importing anything — this is what Zapier calls when the user tests\nthe step while building a Zap."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                oneOf:
                  -
                    description: 'real import'
                    type: object
                    example:
                      message: 'Job started!'
                      job_id: 9f1c8b2e-...
                    properties:
                      message:
                        type: string
                        example: 'Job started!'
                      job_id:
                        type: string
                        example: 9f1c8b2e-...
                  -
                    description: is_test=true
                    type: object
                    example:
                      message: 'Job started!'
                      genpage_url: 'https://myworkspace.genpa.ge/aws-john'
                    properties:
                      message:
                        type: string
                        example: 'Job started!'
                      genpage_url:
                        type: string
                        example: 'https://myworkspace.genpa.ge/aws-john'
        404:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Campaign not found'
                properties:
                  message:
                    type: string
                    example: 'Campaign not found'
      tags:
        - Zapier
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                workspace_id:
                  type: integer
                  description: 'The workspace to add the lead to.'
                  example: 55
                  nullable: false
                campaign_id:
                  type: integer
                  description: 'The campaign to add the lead to.'
                  example: 123
                  nullable: false
                is_test:
                  type: boolean
                  description: 'Return a sample response instead of importing.'
                  example: false
                  nullable: true
                linkedin_profile_url:
                  type: string
                  description: 'One of linkedin_profile_url, company_domain or email is required.'
                  example: 'https://www.linkedin.com/in/williamhgates/'
                  nullable: true
                company_domain:
                  type: string
                  description: 'One of linkedin_profile_url, company_domain or email is required.'
                  example: example.com
                  nullable: true
                email:
                  type: string
                  description: 'One of linkedin_profile_url, company_domain or email is required.'
                  example: test@example.com
                  nullable: true
                callback_url:
                  type: string
                  description: 'Called with the generated page once the import finishes.'
                  example: 'https://example.com/callback'
                  nullable: false
                custom_data:
                  type: object
                  description: 'Key/value pairs stored as variables on the lead.'
                  example:
                    key: value
                  nullable: true
                  properties: {  }
              required:
                - workspace_id
                - campaign_id
                - callback_url
  /api/external/v1/zapier/upsert-lead-basic:
    post:
      summary: 'Create a lead through Zapier (no callback required).'
      operationId: createALeadThroughZapiernoCallbackRequired
      description: "Same as `upsert-lead`, but the callback URL is optional: use this when the\nZap does not need GenPage to call back once the page has been generated."
      parameters: []
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Job started!'
                  job_id: 9f1c8b2e-...
                properties:
                  message:
                    type: string
                    example: 'Job started!'
                  job_id:
                    type: string
                    example: 9f1c8b2e-...
        404:
          description: ''
          content:
            application/json:
              schema:
                type: object
                example:
                  message: 'Campaign not found'
                properties:
                  message:
                    type: string
                    example: 'Campaign not found'
      tags:
        - Zapier
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                workspace_id:
                  type: integer
                  description: 'The workspace to add the lead to.'
                  example: 55
                  nullable: false
                campaign_id:
                  type: integer
                  description: 'The campaign to add the lead to.'
                  example: 123
                  nullable: false
                is_test:
                  type: boolean
                  description: 'Accepted for parity with `upsert-lead`; this endpoint ignores it.'
                  example: false
                  nullable: true
                callback_url:
                  type: string
                  description: 'Called with the generated page once the import finishes.'
                  example: 'https://example.com/callback'
                  nullable: true
                generate_ai_variables:
                  type: boolean
                  description: 'Generate AI variable values for the lead. Defaults to true for this endpoint.'
                  example: true
                  nullable: true
                linkedin_profile_url:
                  type: string
                  description: 'One of linkedin_profile_url, company_domain or email is required.'
                  example: 'https://www.linkedin.com/in/williamhgates/'
                  nullable: true
                company_domain:
                  type: string
                  description: 'One of linkedin_profile_url, company_domain or email is required.'
                  example: example.com
                  nullable: true
                email:
                  type: string
                  description: 'One of linkedin_profile_url, company_domain or email is required.'
                  example: test@example.com
                  nullable: true
                custom_data:
                  type: object
                  description: 'Key/value pairs stored as variables on the lead.'
                  example:
                    key: value
                  nullable: true
                  properties: {  }
              required:
                - workspace_id
                - campaign_id
  /api/external/v1/zapier/get-leads:
    get:
      summary: 'Poll for leads created in a campaign.'
      operationId: pollForLeadsCreatedInACampaign
      description: "Returns the newest leads first. Pass `created_after` and/or `last_lead_id`\nfrom the previous poll to only get what is new since then."
      parameters:
        -
          in: query
          name: workspace_id
          description: 'The workspace to read from.'
          example: 55
          required: true
          schema:
            type: integer
            description: 'The workspace to read from.'
            example: 55
            nullable: false
        -
          in: query
          name: campaign_id
          description: 'The campaign to read from.'
          example: 123
          required: true
          schema:
            type: integer
            description: 'The campaign to read from.'
            example: 123
            nullable: false
        -
          in: query
          name: created_after
          description: 'Only return leads created at or after this timestamp.'
          example: '2026-08-01T00:00:00Z'
          required: false
          schema:
            type: string
            description: 'Only return leads created at or after this timestamp.'
            example: '2026-08-01T00:00:00Z'
            nullable: true
        -
          in: query
          name: last_lead_id
          description: 'Only return leads with an id greater than this.'
          example: 4200
          required: false
          schema:
            type: integer
            description: 'Only return leads with an id greater than this.'
            example: 4200
            nullable: true
        -
          in: query
          name: limit
          description: 'How many leads to return, 1-100. Defaults to 50.'
          example: 50
          required: false
          schema:
            type: integer
            description: 'How many leads to return, 1-100. Defaults to 50.'
            example: 50
            nullable: true
        -
          in: query
          name: is_test
          description: 'Return the most recent lead when the filters match nothing, so a Zap test has sample data.'
          example: false
          required: false
          schema:
            type: boolean
            description: 'Return the most recent lead when the filters match nothing, so a Zap test has sample data.'
            example: false
            nullable: true
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                example:
                  -
                    id: 56789
                    created_at: '2026-08-16T10:00:00.000000Z'
                    genpage_url: 'https://myworkspace.genpa.ge/aws-john'
                    name: 'John Doe'
                    email: john@aws.com
                    company_name: AWS
                    domain: aws.com
                    company_name_slug: aws
      tags:
        - Zapier
  /api/external/v1/zapier/get-form-submissions:
    get:
      summary: 'Poll for recent form submissions.'
      operationId: pollForRecentFormSubmissions
      description: "Without `workspace_id` this returns submissions from every workspace the\nAPI key can reach, newest first."
      parameters:
        -
          in: query
          name: workspace_id
          description: 'The workspace to read from.'
          example: 55
          required: false
          schema:
            type: integer
            description: 'The workspace to read from.'
            example: 55
            nullable: true
        -
          in: query
          name: campaign_id
          description: 'Only return submissions from this campaign.'
          example: 123
          required: false
          schema:
            type: integer
            description: 'Only return submissions from this campaign.'
            example: 123
            nullable: true
        -
          in: query
          name: limit
          description: 'How many submissions to return, 1-100. Defaults to 50.'
          example: 50
          required: false
          schema:
            type: integer
            description: 'How many submissions to return, 1-100. Defaults to 50.'
            example: 50
            nullable: true
      responses:
        200:
          description: ''
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                example:
                  -
                    id: 91
                    form_id: contact
                    page_url: 'https://myworkspace.genpa.ge/aws-john'
                    ip_address: 203.0.113.10
                    created_at: '2026-08-16T10:00:00+00:00'
                    email: john@aws.com
      tags:
        - Zapier
