curl --request PATCH \
--url https://productlane.com/api/v2/docs/articles/{id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"title": "<string>",
"content": "<string>",
"allow_image_removal": true,
"summary": "<string>",
"published": true,
"archived": true,
"show_on_home_page": true,
"group_id": "<string>",
"order": 1,
"parent_article_id": "<string>",
"portal_instance_id": "<string>",
"icon": "<string>",
"url_name": "<string>",
"image_url": "<string>",
"language": "<string>"
}
'import requests
url = "https://productlane.com/api/v2/docs/articles/{id}"
payload = {
"title": "<string>",
"content": "<string>",
"allow_image_removal": True,
"summary": "<string>",
"published": True,
"archived": True,
"show_on_home_page": True,
"group_id": "<string>",
"order": 1,
"parent_article_id": "<string>",
"portal_instance_id": "<string>",
"icon": "<string>",
"url_name": "<string>",
"image_url": "<string>",
"language": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
title: '<string>',
content: '<string>',
allow_image_removal: true,
summary: '<string>',
published: true,
archived: true,
show_on_home_page: true,
group_id: '<string>',
order: 1,
parent_article_id: '<string>',
portal_instance_id: '<string>',
icon: '<string>',
url_name: '<string>',
image_url: '<string>',
language: '<string>'
})
};
fetch('https://productlane.com/api/v2/docs/articles/{id}', 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://productlane.com/api/v2/docs/articles/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'title' => '<string>',
'content' => '<string>',
'allow_image_removal' => true,
'summary' => '<string>',
'published' => true,
'archived' => true,
'show_on_home_page' => true,
'group_id' => '<string>',
'order' => 1,
'parent_article_id' => '<string>',
'portal_instance_id' => '<string>',
'icon' => '<string>',
'url_name' => '<string>',
'image_url' => '<string>',
'language' => '<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://productlane.com/api/v2/docs/articles/{id}"
payload := strings.NewReader("{\n \"title\": \"<string>\",\n \"content\": \"<string>\",\n \"allow_image_removal\": true,\n \"summary\": \"<string>\",\n \"published\": true,\n \"archived\": true,\n \"show_on_home_page\": true,\n \"group_id\": \"<string>\",\n \"order\": 1,\n \"parent_article_id\": \"<string>\",\n \"portal_instance_id\": \"<string>\",\n \"icon\": \"<string>\",\n \"url_name\": \"<string>\",\n \"image_url\": \"<string>\",\n \"language\": \"<string>\"\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://productlane.com/api/v2/docs/articles/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"<string>\",\n \"content\": \"<string>\",\n \"allow_image_removal\": true,\n \"summary\": \"<string>\",\n \"published\": true,\n \"archived\": true,\n \"show_on_home_page\": true,\n \"group_id\": \"<string>\",\n \"order\": 1,\n \"parent_article_id\": \"<string>\",\n \"portal_instance_id\": \"<string>\",\n \"icon\": \"<string>\",\n \"url_name\": \"<string>\",\n \"image_url\": \"<string>\",\n \"language\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://productlane.com/api/v2/docs/articles/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"title\": \"<string>\",\n \"content\": \"<string>\",\n \"allow_image_removal\": true,\n \"summary\": \"<string>\",\n \"published\": true,\n \"archived\": true,\n \"show_on_home_page\": true,\n \"group_id\": \"<string>\",\n \"order\": 1,\n \"parent_article_id\": \"<string>\",\n \"portal_instance_id\": \"<string>\",\n \"icon\": \"<string>\",\n \"url_name\": \"<string>\",\n \"image_url\": \"<string>\",\n \"language\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"created_at": "<string>",
"updated_at": "<string>",
"title": "<string>",
"summary": "<string>",
"content": "<string>",
"icon": "<string>",
"url_name": "<string>",
"published": true,
"visibility": "public",
"visibility_tier": "public",
"kind": "doc",
"external_url": "<string>",
"archived": true,
"show_on_home_page": true,
"image_url": "<string>",
"group_id": "<string>",
"parent_article_id": "<string>",
"order": 123,
"portal_instance_id": "<string>"
}{
"message": "<string>",
"code": "<string>",
"issues": [
{
"message": "<string>"
}
]
}Update docs article
Update a help-center article. content replaces the whole body and is rejected when it leaves out an image the article still has. Pass language to upsert a translation row; non-translatable fields always apply to the base. Requires the docs:write scope.
curl --request PATCH \
--url https://productlane.com/api/v2/docs/articles/{id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"title": "<string>",
"content": "<string>",
"allow_image_removal": true,
"summary": "<string>",
"published": true,
"archived": true,
"show_on_home_page": true,
"group_id": "<string>",
"order": 1,
"parent_article_id": "<string>",
"portal_instance_id": "<string>",
"icon": "<string>",
"url_name": "<string>",
"image_url": "<string>",
"language": "<string>"
}
'import requests
url = "https://productlane.com/api/v2/docs/articles/{id}"
payload = {
"title": "<string>",
"content": "<string>",
"allow_image_removal": True,
"summary": "<string>",
"published": True,
"archived": True,
"show_on_home_page": True,
"group_id": "<string>",
"order": 1,
"parent_article_id": "<string>",
"portal_instance_id": "<string>",
"icon": "<string>",
"url_name": "<string>",
"image_url": "<string>",
"language": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
title: '<string>',
content: '<string>',
allow_image_removal: true,
summary: '<string>',
published: true,
archived: true,
show_on_home_page: true,
group_id: '<string>',
order: 1,
parent_article_id: '<string>',
portal_instance_id: '<string>',
icon: '<string>',
url_name: '<string>',
image_url: '<string>',
language: '<string>'
})
};
fetch('https://productlane.com/api/v2/docs/articles/{id}', 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://productlane.com/api/v2/docs/articles/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'title' => '<string>',
'content' => '<string>',
'allow_image_removal' => true,
'summary' => '<string>',
'published' => true,
'archived' => true,
'show_on_home_page' => true,
'group_id' => '<string>',
'order' => 1,
'parent_article_id' => '<string>',
'portal_instance_id' => '<string>',
'icon' => '<string>',
'url_name' => '<string>',
'image_url' => '<string>',
'language' => '<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://productlane.com/api/v2/docs/articles/{id}"
payload := strings.NewReader("{\n \"title\": \"<string>\",\n \"content\": \"<string>\",\n \"allow_image_removal\": true,\n \"summary\": \"<string>\",\n \"published\": true,\n \"archived\": true,\n \"show_on_home_page\": true,\n \"group_id\": \"<string>\",\n \"order\": 1,\n \"parent_article_id\": \"<string>\",\n \"portal_instance_id\": \"<string>\",\n \"icon\": \"<string>\",\n \"url_name\": \"<string>\",\n \"image_url\": \"<string>\",\n \"language\": \"<string>\"\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://productlane.com/api/v2/docs/articles/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"<string>\",\n \"content\": \"<string>\",\n \"allow_image_removal\": true,\n \"summary\": \"<string>\",\n \"published\": true,\n \"archived\": true,\n \"show_on_home_page\": true,\n \"group_id\": \"<string>\",\n \"order\": 1,\n \"parent_article_id\": \"<string>\",\n \"portal_instance_id\": \"<string>\",\n \"icon\": \"<string>\",\n \"url_name\": \"<string>\",\n \"image_url\": \"<string>\",\n \"language\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://productlane.com/api/v2/docs/articles/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"title\": \"<string>\",\n \"content\": \"<string>\",\n \"allow_image_removal\": true,\n \"summary\": \"<string>\",\n \"published\": true,\n \"archived\": true,\n \"show_on_home_page\": true,\n \"group_id\": \"<string>\",\n \"order\": 1,\n \"parent_article_id\": \"<string>\",\n \"portal_instance_id\": \"<string>\",\n \"icon\": \"<string>\",\n \"url_name\": \"<string>\",\n \"image_url\": \"<string>\",\n \"language\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"created_at": "<string>",
"updated_at": "<string>",
"title": "<string>",
"summary": "<string>",
"content": "<string>",
"icon": "<string>",
"url_name": "<string>",
"published": true,
"visibility": "public",
"visibility_tier": "public",
"kind": "doc",
"external_url": "<string>",
"archived": true,
"show_on_home_page": true,
"image_url": "<string>",
"group_id": "<string>",
"parent_article_id": "<string>",
"order": 123,
"portal_instance_id": "<string>"
}{
"message": "<string>",
"code": "<string>",
"issues": [
{
"message": "<string>"
}
]
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Path Parameters
Body
1Markdown body. Replaces the whole body, so carry over every image, table, embed and tabs block the article already has. Example keys, ids and tokens are placeholders like <your-widget-key />, never a made-up value that looks real. House shape: one ## per section, a --- divider above each one that has content above it, > for a callout, and backticks for a navigation path.
1Defaults to false, which rejects a body that leaves out an image the article still has. Set to true to delete those images.
300agent keeps the article off your docs site while the Productlane Agent still answers from it. internal restricts it to the AI Assistant. unlisted is the former name for agent.
public, agent, internal, unlisted Pass null to detach the article from any group.
Position among its siblings, ascending.
x >= 0Root-level article id to nest this article under as a subpage. null lifts it back to the top level of its group.
Portal instance id to assign, from GET /portal/instances. Omit to follow the group or parent the item belongs to; null targets the Main (Root) portal. A value that disagrees with the group's portal is rejected.
Nucleo icon name in PascalCase.
1 - 64Public docs path, like guides/getting-started. The previous path keeps redirecting to the article.
1 - 200Cover image URL, from POST /api/v2/files. null removes the cover; leaving the field out keeps the current one. The blur placeholder is recomputed.
BCP-47 language code. When set, translatable fields upsert a translation row; non-translatable fields always apply to the base.
Response
Successful response
Name of a Nucleo icon (PascalCase, e.g. Notepad, Atom). Must be a valid icon from https://nucleoapp.com - unknown names will not render in the dashboard or portal.
Whether the article is on your docs site. Deprecated: read visibility_tier for the agent and internal split.
public, unlisted agent and internal articles both stay off your docs site and out of portal search. The Productlane Agent answers customers from an agent article, and never links it. An internal article is read by the AI Assistant alone.
public, agent, internal link rows point at a page you host elsewhere: content is empty and external_url holds the address.
doc, link Position among its siblings, ascending. Sort by it to match the order the docs site renders.