> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devtune.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Create action draft pull request

> Opens a pull request on the customer's content repo through the DevTune GitHub App, or a change request in their GitBook space, from the action's current content draft, or writes a newer draft to the open one. The page belongs to the content source with the longest matching URL prefix, and the source's provider decides which. One per action; DevTune writes only to its own branch or change request and never merges. A refresh draft's changes are applied to the page, matched after collapsing whitespace; if any does not match, nothing is written. A create draft becomes a new page named from the brief's target. A GitBook change request's description names who approved the draft, and DevTune checks GitBook stored the page as written. The pull request is read from GET /projects/{projectId}/actions/{actionId}/draft. A refusal is a 409 with its reason: no_draft, draft_not_latest, action_closed (live or archived), page_locked, no_content_source (details.sources lists the sources; retry with sourceId), source_needs_reconnect, file_not_found (details.tried lists what was tried; retry with filePath for GitHub or pagePath for GitBook), file_exists, draft_does_not_match_source (details.changes names the changes), branch_diverged (someone else pushed to DevTune's branch), change_request_diverged (someone else edited the change request), change_request_conflicts (the change request has conflicts in GitBook), page_not_preserved (GitBook stored the page differently), pull_request_in_progress or pull_request_merged; 400 for invalid_file_path; 403 when content pull requests are off; 503 for github_error or gitbook_error (details.detail is rate_limited when GitBook's rate limit for the connection is used up, recovery_incomplete when DevTune could not finish looking for a change request an earlier attempt may have opened, or recovery_stale when another attempt for the action finished while this one started; retry later). The API key must have been created by a member of the project with project management permission; otherwise 403. Requires the `actions.write` scope.



## OpenAPI

````yaml /openapi.json post /projects/{projectId}/actions/{actionId}/draft/pull-request
openapi: 3.1.0
info:
  title: DevTune API
  version: 2.0.0
  description: >-
    API for programmatic access to your AI visibility data, webhook
    subscriptions, and automation workflows. Use this API to integrate DevTune
    data into CI/CD pipelines, BI tools, AI agents, and operational systems.
servers:
  - url: https://devtune.ai/api/v2
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Connection and usage
    description: >-
      The project a credential is bound to, its scopes and features, usage, and
      code-mode receipts.
  - name: Setup
    description: >-
      Brands, domains, brand terms, platforms, content sources and pausing a
      project.
  - name: Prompts and topics
    description: Tracked prompts, their topics, and prompt-set analysis.
  - name: Visibility
    description: >-
      Visibility metrics, AI answers, sentiment, competitive position and the
      project timeline.
  - name: Citations
    description: Citation statistics and the most-cited domains and pages.
  - name: Positioning
    description: How well AI answers match your positioning statements.
  - name: Accuracy
    description: Claims AI answers make about your brand, and contradictions.
  - name: Content gaps
    description: Topics, sources and brands where competitors are cited.
  - name: AI Traffic
    description: >-
      AI referrals, answer fetches, crawls, 404 Demand, Direct lift and Search
      Console totals.
  - name: Adoption
    description: npm downloads and GitHub stars for project domains.
  - name: Audit and pages
    description: Audit findings, Google eligibility, page metrics, and locked pages.
  - name: Actions
    description: Suggested and accepted work, briefs, drafts and pull requests.
  - name: Results
    description: Content changes, measured results and what works.
  - name: Agents
    description: Managed agents, their schedules and runs.
  - name: Dex
    description: Private Dex conversations, specialist handoffs and memory.
  - name: Agent Picks
    description: Agent Picks setup, tests, schedules and results.
  - name: Library and Knowledge
    description: Library items and the Knowledge Profile.
  - name: Webhooks
    description: Webhook subscriptions and signing secrets.
  - name: Agent registration
    description: Setup drafts for an unclaimed agent registration.
paths:
  /projects/{projectId}/actions/{actionId}/draft/pull-request:
    post:
      tags:
        - Actions
      summary: Create action draft pull request
      description: >-
        Opens a pull request on the customer's content repo through the DevTune
        GitHub App, or a change request in their GitBook space, from the
        action's current content draft, or writes a newer draft to the open one.
        The page belongs to the content source with the longest matching URL
        prefix, and the source's provider decides which. One per action; DevTune
        writes only to its own branch or change request and never merges. A
        refresh draft's changes are applied to the page, matched after
        collapsing whitespace; if any does not match, nothing is written. A
        create draft becomes a new page named from the brief's target. A GitBook
        change request's description names who approved the draft, and DevTune
        checks GitBook stored the page as written. The pull request is read from
        GET /projects/{projectId}/actions/{actionId}/draft. A refusal is a 409
        with its reason: no_draft, draft_not_latest, action_closed (live or
        archived), page_locked, no_content_source (details.sources lists the
        sources; retry with sourceId), source_needs_reconnect, file_not_found
        (details.tried lists what was tried; retry with filePath for GitHub or
        pagePath for GitBook), file_exists, draft_does_not_match_source
        (details.changes names the changes), branch_diverged (someone else
        pushed to DevTune's branch), change_request_diverged (someone else
        edited the change request), change_request_conflicts (the change request
        has conflicts in GitBook), page_not_preserved (GitBook stored the page
        differently), pull_request_in_progress or pull_request_merged; 400 for
        invalid_file_path; 403 when content pull requests are off; 503 for
        github_error or gitbook_error (details.detail is rate_limited when
        GitBook's rate limit for the connection is used up, recovery_incomplete
        when DevTune could not finish looking for a change request an earlier
        attempt may have opened, or recovery_stale when another attempt for the
        action finished while this one started; retry later). The API key must
        have been created by a member of the project with project management
        permission; otherwise 403. Requires the `actions.write` scope.
      operationId: createActionPullRequest
      parameters:
        - name: projectId
          in: path
          required: true
          description: >-
            The project the credential is bound to. Read it from GET
            /connection.
          schema:
            type: string
            format: uuid
        - name: actionId
          in: path
          required: true
          description: UUID of the action.
          schema:
            type: string
            format: uuid
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                draftId:
                  type: string
                  format: uuid
                  description: >-
                    The current draft version id from the draft read; refused
                    with draft_not_latest if a newer draft replaced it.
                sourceId:
                  type: string
                  format: uuid
                  description: >-
                    A content source id from GET
                    /projects/{projectId}/setup/content-sources, for a page no
                    source covers.
                filePath:
                  type: string
                  minLength: 1
                  maxLength: 1000
                  description: >-
                    The repo file to edit or create, under the source's folder,
                    when DevTune cannot find or name it. GitHub sources only.
                pagePath:
                  type: string
                  minLength: 1
                  maxLength: 1000
                  description: >-
                    The GitBook page path to edit or create, below the space
                    root, such as guides/quickstart, when DevTune cannot find or
                    name it. GitBook sources only.
      responses:
        '200':
          description: Action draft pull request
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/ActionPullRequestData'
                  meta:
                    $ref: '#/components/schemas/Meta'
                required:
                  - data
                  - meta
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '403':
          $ref: '#/components/responses/ForbiddenError'
        '404':
          $ref: '#/components/responses/NotFoundError'
        '409':
          $ref: '#/components/responses/ConflictError'
        '429':
          $ref: '#/components/responses/RateLimitExceededError'
        '500':
          $ref: '#/components/responses/ServerError'
        '503':
          description: GitHub or GitBook refused the request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    ActionPullRequestData:
      type: object
      properties:
        pullRequest:
          description: The pull request.
          oneOf:
            - $ref: '#/components/schemas/ActionPullRequest'
            - type: 'null'
      required:
        - pullRequest
    Meta:
      type: object
      description: Sent beside data on every successful response that returns data.
      properties:
        timestamp:
          type: string
          format: date-time
          description: When the response was produced.
        projectId:
          type: string
          format: uuid
    Error:
      type: object
      properties:
        error:
          type: string
          description: >-
            Machine-readable error code, such as bad_request, unauthorized,
            forbidden, not_found, conflict, payment_required,
            rate_limit_exceeded or internal_error. Some endpoints return their
            own codes, listed in their descriptions.
        message:
          type: string
          description: >-
            What went wrong, for a person to read. Do not parse it; use error
            and reason.
        reason:
          type: string
          description: >-
            Why the request was refused, for an error with more than one cause,
            such as a refused content-draft start.
        details:
          type: object
          additionalProperties: true
          description: >-
            Machine-readable facts about the refusal, such as shortfall_credits
            when an Agent Picks start is refused for insufficient_credits.
        status:
          type: integer
          description: The HTTP status code, repeated in the body.
      required:
        - error
        - message
        - status
    ActionPullRequest:
      type: object
      properties:
        id:
          type: string
          format: uuid
        provider:
          type: string
          enum:
            - github
            - gitbook
          description: >-
            github for a pull request on a content repo, gitbook for a change
            request in a GitBook space.
        state:
          type: string
          enum:
            - opening
            - open
            - merged
            - closed
            - failed
          description: >-
            opening while DevTune writes it, open once GitHub or GitBook created
            it, merged or closed as DevTune last read it, failed when GitHub or
            GitBook refused the attempt or an automatic attempt was refused. A
            GitBook change request archived in GitBook is closed. DevTune never
            merges.
        number:
          type:
            - integer
            - 'null'
          description: >-
            The pull request or change request number. Null until it was
            created.
        url:
          type:
            - string
            - 'null'
          format: uri
          description: >-
            The pull request on GitHub, or the change request in GitBook. Null
            until it was created.
        repository:
          type:
            - string
            - 'null'
          description: The repo, as owner/name. Null for GitBook.
        branch:
          type:
            - string
            - 'null'
          description: DevTune's branch, devtune/action-<id>. Null for GitBook.
        space:
          description: The GitBook space. Null for GitHub.
          oneOf:
            - type: object
              additionalProperties: false
              required:
                - id
                - title
              properties:
                id:
                  type: string
                title:
                  type: string
            - type: 'null'
        filePath:
          type:
            - string
            - 'null'
          description: >-
            The repo file the pull request edits or creates, or the GitBook page
            path the change request edits or creates; null for a failed
            automatic attempt that found no file.
        isNewFile:
          type: boolean
          description: True when the pull request creates filePath rather than editing it.
        draftId:
          type: string
          format: uuid
          description: The draft version the pull request carries.
        trigger:
          type: string
          enum:
            - app
            - api
            - mcp
            - auto
          description: >-
            auto when DevTune opened it for a new draft, because the content
            source has automatic pull requests on.
        failure:
          type:
            - object
            - 'null'
          description: >-
            Why the attempt failed. An automatic attempt also records the
            refusals no one saw: source_needs_reconnect, file_not_found,
            file_exists and draft_does_not_match_source. A GitBook attempt can
            also fail with gitbook_error, change_request_diverged,
            page_not_preserved, or disconnected when GitBook was disconnected in
            DevTune. Null unless state is failed.
          properties:
            code:
              type: string
              enum:
                - branch_diverged
                - github_error
                - source_needs_reconnect
                - file_not_found
                - file_exists
                - draft_does_not_match_source
                - gitbook_error
                - change_request_diverged
                - change_request_conflicts
                - page_not_preserved
                - disconnected
            detail:
              type:
                - string
                - 'null'
              description: More about the failure. Null when there is none.
          required:
            - code
            - detail
        createdAt:
          type: string
          format: date-time
        openedAt:
          type:
            - string
            - 'null'
          format: date-time
          description: When GitHub created the pull request. Null until then.
        mergedAt:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            When DevTune recorded the pull request merged in GitHub. Null unless
            merged.
        closedAt:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            When DevTune recorded the pull request closed. Null unless it was
            closed; a pull request closed, then reopened and merged in GitHub,
            keeps this time.
        checkedAt:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            When DevTune last read this GitBook change request in GitBook and
            GitBook answered. Null for a GitHub pull request and until the first
            read.
        updateFailure:
          description: >-
            The latest update DevTune could not write to an open GitBook change
            request, while DevTune has not written to it since:
            change_request_diverged (someone else edited it),
            change_request_conflicts (its rebase left conflicts) or
            page_not_preserved (GitBook stored the page differently). The change
            request stays open. Null otherwise.
          oneOf:
            - type: object
              additionalProperties: false
              required:
                - code
                - detail
                - draftId
                - createdAt
              properties:
                code:
                  type: string
                  enum:
                    - change_request_diverged
                    - change_request_conflicts
                    - page_not_preserved
                detail:
                  type:
                    - string
                    - 'null'
                draftId:
                  type: string
                  format: uuid
                createdAt:
                  type: string
                  format: date-time
            - type: 'null'
      required:
        - id
        - provider
        - state
        - number
        - url
        - repository
        - branch
        - space
        - filePath
        - isNewFile
        - draftId
        - trigger
        - failure
        - createdAt
        - openedAt
        - mergedAt
        - closedAt
        - checkedAt
        - updateFailure
  responses:
    BadRequestError:
      description: >-
        The request is invalid: a parameter or body field is missing, has the
        wrong type or is out of range, or a cursor doesn't match this list. The
        message says which; reason, where present, is listed in the endpoint's
        description. Fix the request before retrying, and restart a list without
        its cursor. See [Errors](/api-reference/errors).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    UnauthorizedError:
      description: >-
        The request has no valid credential: the Authorization header is missing
        or malformed, or the API key or OAuth token is invalid, expired or
        revoked. Send `Authorization: Bearer <API key>` with an active key, or
        sign in again to get a new OAuth token. See
        [Errors](/api-reference/errors).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ForbiddenError:
      description: >-
        The credential is valid but can't make this request. The message says
        which cause applies: the key or sign-in lacks the scope this endpoint
        requires (named in the message), it belongs to another project, the plan
        doesn't include API access or this feature, the project is paused (a
        paused project keeps only read scopes and setup.write), or the member a
        write acts as no longer has the role it needs. Read `GET
        /projects/{projectId}/connection` for the credential's current scopes
        and features, then use a key that has the scope, sign in again and
        approve it, or upgrade the plan. See [Errors](/api-reference/errors).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFoundError:
      description: >-
        The resource doesn't exist in this project, was deleted, or the
        credential can't see it. Check the IDs in the path, and that the
        projectId is the project the credential is bound to. See
        [Errors](/api-reference/errors).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ConflictError:
      description: >-
        The request conflicts with the resource's current state. The message,
        and reason where present, say what conflicts; the endpoint's description
        lists its reasons. Read the resource again, then change the request.
        When the body has retryable true, send the same request again. See
        [Errors](/api-reference/errors).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RateLimitExceededError:
      description: >-
        Too many requests from this credential in the current window. The
        request was refused before it took effect, so it is safe to retry: wait
        until the time in X-RateLimit-Reset, then send it again. Endpoints that
        start agent runs have a stricter limit. See [Rate
        limits](/api-reference/rate-limits).
      headers:
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  headers:
    X-RateLimit-Limit:
      description: Maximum requests per window
      schema:
        type: integer
    X-RateLimit-Remaining:
      description: Requests remaining in current window
      schema:
        type: integer
    X-RateLimit-Reset:
      description: Unix timestamp when the window resets
      schema:
        type: integer
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        API key with dtk_live_ prefix. Obtain it from API Keys in the account
        sidebar. New keys start with all supported scopes selected for the
        chosen project, and you can narrow them to specific read/write scopes as
        needed.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.