curl --request POST \
--url https://productlane.com/api/v2/docs/articles \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"title": "<string>",
"content": "<string>",
"summary": "<string>",
"group_id": "<string>",
"parent_article_id": "<string>",
"portal_instance_id": "<string>",
"order": 1,
"published": true,
"icon": "<string>",
"image_url": "<string>",
"language": "<string>"
}
'import requests
url = "https://productlane.com/api/v2/docs/articles"
payload = {
"title": "<string>",
"content": "<string>",
"summary": "<string>",
"group_id": "<string>",
"parent_article_id": "<string>",
"portal_instance_id": "<string>",
"order": 1,
"published": True,
"icon": "<string>",
"image_url": "<string>",
"language": "<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({
title: '<string>',
content: '<string>',
summary: '<string>',
group_id: '<string>',
parent_article_id: '<string>',
portal_instance_id: '<string>',
order: 1,
published: true,
icon: '<string>',
image_url: '<string>',
language: '<string>'
})
};
fetch('https://productlane.com/api/v2/docs/articles', 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",
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([
'title' => '<string>',
'content' => '<string>',
'summary' => '<string>',
'group_id' => '<string>',
'parent_article_id' => '<string>',
'portal_instance_id' => '<string>',
'order' => 1,
'published' => true,
'icon' => '<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"
payload := strings.NewReader("{\n \"title\": \"<string>\",\n \"content\": \"<string>\",\n \"summary\": \"<string>\",\n \"group_id\": \"<string>\",\n \"parent_article_id\": \"<string>\",\n \"portal_instance_id\": \"<string>\",\n \"order\": 1,\n \"published\": true,\n \"icon\": \"<string>\",\n \"image_url\": \"<string>\",\n \"language\": \"<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://productlane.com/api/v2/docs/articles")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"<string>\",\n \"content\": \"<string>\",\n \"summary\": \"<string>\",\n \"group_id\": \"<string>\",\n \"parent_article_id\": \"<string>\",\n \"portal_instance_id\": \"<string>\",\n \"order\": 1,\n \"published\": true,\n \"icon\": \"<string>\",\n \"image_url\": \"<string>\",\n \"language\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://productlane.com/api/v2/docs/articles")
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 \"title\": \"<string>\",\n \"content\": \"<string>\",\n \"summary\": \"<string>\",\n \"group_id\": \"<string>\",\n \"parent_article_id\": \"<string>\",\n \"portal_instance_id\": \"<string>\",\n \"order\": 1,\n \"published\": true,\n \"icon\": \"<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>"
}
]
}Create docs article
Create a help-center article. Pass language to create a translation row instead of populating the base. Requires the docs:write scope.
curl --request POST \
--url https://productlane.com/api/v2/docs/articles \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"title": "<string>",
"content": "<string>",
"summary": "<string>",
"group_id": "<string>",
"parent_article_id": "<string>",
"portal_instance_id": "<string>",
"order": 1,
"published": true,
"icon": "<string>",
"image_url": "<string>",
"language": "<string>"
}
'import requests
url = "https://productlane.com/api/v2/docs/articles"
payload = {
"title": "<string>",
"content": "<string>",
"summary": "<string>",
"group_id": "<string>",
"parent_article_id": "<string>",
"portal_instance_id": "<string>",
"order": 1,
"published": True,
"icon": "<string>",
"image_url": "<string>",
"language": "<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({
title: '<string>',
content: '<string>',
summary: '<string>',
group_id: '<string>',
parent_article_id: '<string>',
portal_instance_id: '<string>',
order: 1,
published: true,
icon: '<string>',
image_url: '<string>',
language: '<string>'
})
};
fetch('https://productlane.com/api/v2/docs/articles', 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",
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([
'title' => '<string>',
'content' => '<string>',
'summary' => '<string>',
'group_id' => '<string>',
'parent_article_id' => '<string>',
'portal_instance_id' => '<string>',
'order' => 1,
'published' => true,
'icon' => '<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"
payload := strings.NewReader("{\n \"title\": \"<string>\",\n \"content\": \"<string>\",\n \"summary\": \"<string>\",\n \"group_id\": \"<string>\",\n \"parent_article_id\": \"<string>\",\n \"portal_instance_id\": \"<string>\",\n \"order\": 1,\n \"published\": true,\n \"icon\": \"<string>\",\n \"image_url\": \"<string>\",\n \"language\": \"<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://productlane.com/api/v2/docs/articles")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"<string>\",\n \"content\": \"<string>\",\n \"summary\": \"<string>\",\n \"group_id\": \"<string>\",\n \"parent_article_id\": \"<string>\",\n \"portal_instance_id\": \"<string>\",\n \"order\": 1,\n \"published\": true,\n \"icon\": \"<string>\",\n \"image_url\": \"<string>\",\n \"language\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://productlane.com/api/v2/docs/articles")
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 \"title\": \"<string>\",\n \"content\": \"<string>\",\n \"summary\": \"<string>\",\n \"group_id\": \"<string>\",\n \"parent_article_id\": \"<string>\",\n \"portal_instance_id\": \"<string>\",\n \"order\": 1,\n \"published\": true,\n \"icon\": \"<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.
Body
1Markdown body. Tabs and code groups use the and tags. 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.
1300Required unless parent_article_id is set, in which case the article joins the parent's group.
1Root-level article id to nest this article under as a subpage. Subpages nest one level deep, join their parent's group and portal, and are never more visible than their parent.
1Portal instance id to assign, from GET /docs/portals. Omit to inherit the parent's or the group's portal; null forces the Main (Root) portal.
Position among its siblings, ascending. A subpage defaults to the end of its parent's subpages, any other article to the top of its group.
x >= 0Defaults to public. agent keeps the article off your docs site while the Productlane Agent still answers from it; internal restricts it to the AI Assistant.
public, agent, internal, unlisted Nucleo icon name in PascalCase (e.g. FilePen). Defaults to Page2.
1 - 64Cover image URL. Must be a file you uploaded through POST /api/v2/files, so it sits on our uploads domain. The blur placeholder the portal shows is computed for you.
BCP-47 language code. When set, the article is created with the body on a translation row and the base row stays empty.
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.