curl --request PUT \
--url https://api.parallellabs.app/api/v0/websites/{websiteId}/file \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"companyId": "<string>",
"path": "<string>",
"content": "<string>",
"branch": "<string>",
"metadata": {}
}
'import requests
url = "https://api.parallellabs.app/api/v0/websites/{websiteId}/file"
payload = {
"companyId": "<string>",
"path": "<string>",
"content": "<string>",
"branch": "<string>",
"metadata": {}
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
companyId: '<string>',
path: '<string>',
content: '<string>',
branch: '<string>',
metadata: {}
})
};
fetch('https://api.parallellabs.app/api/v0/websites/{websiteId}/file', 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://api.parallellabs.app/api/v0/websites/{websiteId}/file",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'companyId' => '<string>',
'path' => '<string>',
'content' => '<string>',
'branch' => '<string>',
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$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://api.parallellabs.app/api/v0/websites/{websiteId}/file"
payload := strings.NewReader("{\n \"companyId\": \"<string>\",\n \"path\": \"<string>\",\n \"content\": \"<string>\",\n \"branch\": \"<string>\",\n \"metadata\": {}\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
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.put("https://api.parallellabs.app/api/v0/websites/{websiteId}/file")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"companyId\": \"<string>\",\n \"path\": \"<string>\",\n \"content\": \"<string>\",\n \"branch\": \"<string>\",\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.parallellabs.app/api/v0/websites/{websiteId}/file")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"companyId\": \"<string>\",\n \"path\": \"<string>\",\n \"content\": \"<string>\",\n \"branch\": \"<string>\",\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"ok": true
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}Write a website file onto a review branch
Applies a fix. The branch is REQUIRED and must not be “main”: the change lands on a review branch the owner approves, never the live site. The branch is created automatically on the first write. The site cannot be published from the API — draft-only.
curl --request PUT \
--url https://api.parallellabs.app/api/v0/websites/{websiteId}/file \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"companyId": "<string>",
"path": "<string>",
"content": "<string>",
"branch": "<string>",
"metadata": {}
}
'import requests
url = "https://api.parallellabs.app/api/v0/websites/{websiteId}/file"
payload = {
"companyId": "<string>",
"path": "<string>",
"content": "<string>",
"branch": "<string>",
"metadata": {}
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
companyId: '<string>',
path: '<string>',
content: '<string>',
branch: '<string>',
metadata: {}
})
};
fetch('https://api.parallellabs.app/api/v0/websites/{websiteId}/file', 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://api.parallellabs.app/api/v0/websites/{websiteId}/file",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'companyId' => '<string>',
'path' => '<string>',
'content' => '<string>',
'branch' => '<string>',
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$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://api.parallellabs.app/api/v0/websites/{websiteId}/file"
payload := strings.NewReader("{\n \"companyId\": \"<string>\",\n \"path\": \"<string>\",\n \"content\": \"<string>\",\n \"branch\": \"<string>\",\n \"metadata\": {}\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
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.put("https://api.parallellabs.app/api/v0/websites/{websiteId}/file")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"companyId\": \"<string>\",\n \"path\": \"<string>\",\n \"content\": \"<string>\",\n \"branch\": \"<string>\",\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.parallellabs.app/api/v0/websites/{websiteId}/file")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"companyId\": \"<string>\",\n \"path\": \"<string>\",\n \"content\": \"<string>\",\n \"branch\": \"<string>\",\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"ok": true
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}{
"error": "<string>"
}Authorizations
Company API key - scoped to a specific company. Generate from the Integrations page in your dashboard.
Path Parameters
Body
Write a website file
Company ID that owns the website
Absolute file path within the site, e.g. /pages/about.html
Full new file content
Review branch to read from or write to. Omit (or "main") to read the live site. To propose fixes, write files to a NEW branch name (e.g. "seo-optimizer-2026-09-03") — the branch is created on first write and is reviewed and approved by the owner. Writing to "main" is refused. Required here and must not be "main".
Structured metadata stored on this file row. For page HTML files: {title, description, seo: {pageType, image, noindex, faq}}. Omit to preserve existing metadata; pass null to clear it.
Response
{ok: true}

