curl --request POST \
--url https://devtune.ai/api/v2/projects/{projectId}/actions/{actionId}/draft/pull-request \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"draftId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"sourceId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"filePath": "<string>",
"pagePath": "<string>"
}
'import requests
url = "https://devtune.ai/api/v2/projects/{projectId}/actions/{actionId}/draft/pull-request"
payload = {
"draftId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"sourceId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"filePath": "<string>",
"pagePath": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
draftId: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
sourceId: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
filePath: '<string>',
pagePath: '<string>'
})
};
fetch('https://devtune.ai/api/v2/projects/{projectId}/actions/{actionId}/draft/pull-request', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://devtune.ai/api/v2/projects/{projectId}/actions/{actionId}/draft/pull-request",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'draftId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'sourceId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'filePath' => '<string>',
'pagePath' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://devtune.ai/api/v2/projects/{projectId}/actions/{actionId}/draft/pull-request"
payload := strings.NewReader("{\n \"draftId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"sourceId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"filePath\": \"<string>\",\n \"pagePath\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://devtune.ai/api/v2/projects/{projectId}/actions/{actionId}/draft/pull-request")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"draftId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"sourceId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"filePath\": \"<string>\",\n \"pagePath\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://devtune.ai/api/v2/projects/{projectId}/actions/{actionId}/draft/pull-request")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"draftId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"sourceId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"filePath\": \"<string>\",\n \"pagePath\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"pullRequest": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"provider": "github",
"state": "opening",
"number": 123,
"url": "<string>",
"repository": "<string>",
"branch": "<string>",
"space": {
"id": "<string>",
"title": "<string>"
},
"filePath": "<string>",
"isNewFile": true,
"draftId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"trigger": "app",
"failure": {
"code": "branch_diverged",
"detail": "<string>"
},
"createdAt": "2023-11-07T05:31:56Z",
"openedAt": "2023-11-07T05:31:56Z",
"mergedAt": "2023-11-07T05:31:56Z",
"closedAt": "2023-11-07T05:31:56Z",
"checkedAt": "2023-11-07T05:31:56Z",
"updateFailure": {
"code": "change_request_diverged",
"detail": "<string>",
"draftId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"createdAt": "2023-11-07T05:31:56Z"
}
}
},
"meta": {
"timestamp": "2023-11-07T05:31:56Z",
"projectId": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": "<string>",
"message": "<string>",
"status": 123,
"reason": "<string>",
"details": {}
}{
"error": "<string>",
"message": "<string>",
"status": 123,
"reason": "<string>",
"details": {}
}{
"error": "<string>",
"message": "<string>",
"status": 123,
"reason": "<string>",
"details": {}
}{
"error": "<string>",
"message": "<string>",
"status": 123,
"reason": "<string>",
"details": {}
}{
"error": "<string>",
"message": "<string>",
"status": 123,
"reason": "<string>",
"details": {}
}{
"error": "<string>",
"message": "<string>",
"status": 123,
"reason": "<string>",
"details": {}
}{
"error": "<string>",
"message": "<string>",
"status": 123,
"reason": "<string>",
"details": {}
}{
"error": "<string>",
"message": "<string>",
"status": 123,
"reason": "<string>",
"details": {}
}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//actions//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.
curl --request POST \
--url https://devtune.ai/api/v2/projects/{projectId}/actions/{actionId}/draft/pull-request \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"draftId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"sourceId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"filePath": "<string>",
"pagePath": "<string>"
}
'import requests
url = "https://devtune.ai/api/v2/projects/{projectId}/actions/{actionId}/draft/pull-request"
payload = {
"draftId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"sourceId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"filePath": "<string>",
"pagePath": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
draftId: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
sourceId: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
filePath: '<string>',
pagePath: '<string>'
})
};
fetch('https://devtune.ai/api/v2/projects/{projectId}/actions/{actionId}/draft/pull-request', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://devtune.ai/api/v2/projects/{projectId}/actions/{actionId}/draft/pull-request",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'draftId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'sourceId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'filePath' => '<string>',
'pagePath' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://devtune.ai/api/v2/projects/{projectId}/actions/{actionId}/draft/pull-request"
payload := strings.NewReader("{\n \"draftId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"sourceId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"filePath\": \"<string>\",\n \"pagePath\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://devtune.ai/api/v2/projects/{projectId}/actions/{actionId}/draft/pull-request")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"draftId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"sourceId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"filePath\": \"<string>\",\n \"pagePath\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://devtune.ai/api/v2/projects/{projectId}/actions/{actionId}/draft/pull-request")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"draftId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"sourceId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"filePath\": \"<string>\",\n \"pagePath\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"pullRequest": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"provider": "github",
"state": "opening",
"number": 123,
"url": "<string>",
"repository": "<string>",
"branch": "<string>",
"space": {
"id": "<string>",
"title": "<string>"
},
"filePath": "<string>",
"isNewFile": true,
"draftId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"trigger": "app",
"failure": {
"code": "branch_diverged",
"detail": "<string>"
},
"createdAt": "2023-11-07T05:31:56Z",
"openedAt": "2023-11-07T05:31:56Z",
"mergedAt": "2023-11-07T05:31:56Z",
"closedAt": "2023-11-07T05:31:56Z",
"checkedAt": "2023-11-07T05:31:56Z",
"updateFailure": {
"code": "change_request_diverged",
"detail": "<string>",
"draftId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"createdAt": "2023-11-07T05:31:56Z"
}
}
},
"meta": {
"timestamp": "2023-11-07T05:31:56Z",
"projectId": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
}{
"error": "<string>",
"message": "<string>",
"status": 123,
"reason": "<string>",
"details": {}
}{
"error": "<string>",
"message": "<string>",
"status": 123,
"reason": "<string>",
"details": {}
}{
"error": "<string>",
"message": "<string>",
"status": 123,
"reason": "<string>",
"details": {}
}{
"error": "<string>",
"message": "<string>",
"status": 123,
"reason": "<string>",
"details": {}
}{
"error": "<string>",
"message": "<string>",
"status": 123,
"reason": "<string>",
"details": {}
}{
"error": "<string>",
"message": "<string>",
"status": 123,
"reason": "<string>",
"details": {}
}{
"error": "<string>",
"message": "<string>",
"status": 123,
"reason": "<string>",
"details": {}
}{
"error": "<string>",
"message": "<string>",
"status": 123,
"reason": "<string>",
"details": {}
}Authorizations
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.
Path Parameters
The project the credential is bound to. Read it from GET /connection.
UUID of the action.
Body
The current draft version id from the draft read; refused with draft_not_latest if a newer draft replaced it.
A content source id from GET /projects/{projectId}/setup/content-sources, for a page no source covers.
The repo file to edit or create, under the source's folder, when DevTune cannot find or name it. GitHub sources only.
1 - 1000The 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.
1 - 1000