curl --request POST \
--url https://api.scripe.io/v1/posts/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"projectId": "proj_a1b2c3d4e5f6g7h8",
"source": {
"type": "text",
"text": "<string>"
},
"scheduledFor": "2023-11-07T05:31:56Z",
"options": {
"language": "<string>"
},
"wait_for_completion_ms": 12500
}
'import requests
url = "https://api.scripe.io/v1/posts/generations"
payload = {
"projectId": "proj_a1b2c3d4e5f6g7h8",
"source": {
"type": "text",
"text": "<string>"
},
"scheduledFor": "2023-11-07T05:31:56Z",
"options": { "language": "<string>" },
"wait_for_completion_ms": 12500
}
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({
projectId: 'proj_a1b2c3d4e5f6g7h8',
source: {type: 'text', text: '<string>'},
scheduledFor: '2023-11-07T05:31:56Z',
options: {language: '<string>'},
wait_for_completion_ms: 12500
})
};
fetch('https://api.scripe.io/v1/posts/generations', 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.scripe.io/v1/posts/generations",
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([
'projectId' => 'proj_a1b2c3d4e5f6g7h8',
'source' => [
'type' => 'text',
'text' => '<string>'
],
'scheduledFor' => '2023-11-07T05:31:56Z',
'options' => [
'language' => '<string>'
],
'wait_for_completion_ms' => 12500
]),
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://api.scripe.io/v1/posts/generations"
payload := strings.NewReader("{\n \"projectId\": \"proj_a1b2c3d4e5f6g7h8\",\n \"source\": {\n \"type\": \"text\",\n \"text\": \"<string>\"\n },\n \"scheduledFor\": \"2023-11-07T05:31:56Z\",\n \"options\": {\n \"language\": \"<string>\"\n },\n \"wait_for_completion_ms\": 12500\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://api.scripe.io/v1/posts/generations")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"projectId\": \"proj_a1b2c3d4e5f6g7h8\",\n \"source\": {\n \"type\": \"text\",\n \"text\": \"<string>\"\n },\n \"scheduledFor\": \"2023-11-07T05:31:56Z\",\n \"options\": {\n \"language\": \"<string>\"\n },\n \"wait_for_completion_ms\": 12500\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.scripe.io/v1/posts/generations")
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 \"projectId\": \"proj_a1b2c3d4e5f6g7h8\",\n \"source\": {\n \"type\": \"text\",\n \"text\": \"<string>\"\n },\n \"scheduledFor\": \"2023-11-07T05:31:56Z\",\n \"options\": {\n \"language\": \"<string>\"\n },\n \"wait_for_completion_ms\": 12500\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "job_a1b2c3d4e5f6g7h8",
"type": "POST_GENERATION",
"status": "QUEUED",
"projectId": "<string>",
"startedAt": "2023-11-07T05:31:56Z",
"completedAt": "2023-11-07T05:31:56Z",
"progress": {
"progress": 0.5,
"updatedAt": "2023-11-07T05:31:56Z",
"message": "<string>"
},
"result": {},
"errorCode": "<string>",
"errorMessage": "<string>",
"attemptCount": 1,
"estimatedCompletionMs": 123,
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}Generate a LinkedIn post asynchronously
Kick off an AI-driven post generation. The handler validates
input, reserves AI-spend capacity, enqueues an async job, and
returns a Job envelope. The customer polls
GET /v1/jobs/{jobId} until status transitions to DONE
or FAILED.
Cost: counts against the daily AI-spend cap (~5¢ per call, reconciled with provider actuals after the job runs).
wait_for_completion_ms is a soft hint — the server polls
for up to that many milliseconds (capped at 25 000 ms) before
returning. The response shape is identical regardless;
sync-wait callers receive a DONE status when lucky and a
RUNNING/QUEUED status otherwise.
curl --request POST \
--url https://api.scripe.io/v1/posts/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"projectId": "proj_a1b2c3d4e5f6g7h8",
"source": {
"type": "text",
"text": "<string>"
},
"scheduledFor": "2023-11-07T05:31:56Z",
"options": {
"language": "<string>"
},
"wait_for_completion_ms": 12500
}
'import requests
url = "https://api.scripe.io/v1/posts/generations"
payload = {
"projectId": "proj_a1b2c3d4e5f6g7h8",
"source": {
"type": "text",
"text": "<string>"
},
"scheduledFor": "2023-11-07T05:31:56Z",
"options": { "language": "<string>" },
"wait_for_completion_ms": 12500
}
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({
projectId: 'proj_a1b2c3d4e5f6g7h8',
source: {type: 'text', text: '<string>'},
scheduledFor: '2023-11-07T05:31:56Z',
options: {language: '<string>'},
wait_for_completion_ms: 12500
})
};
fetch('https://api.scripe.io/v1/posts/generations', 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.scripe.io/v1/posts/generations",
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([
'projectId' => 'proj_a1b2c3d4e5f6g7h8',
'source' => [
'type' => 'text',
'text' => '<string>'
],
'scheduledFor' => '2023-11-07T05:31:56Z',
'options' => [
'language' => '<string>'
],
'wait_for_completion_ms' => 12500
]),
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://api.scripe.io/v1/posts/generations"
payload := strings.NewReader("{\n \"projectId\": \"proj_a1b2c3d4e5f6g7h8\",\n \"source\": {\n \"type\": \"text\",\n \"text\": \"<string>\"\n },\n \"scheduledFor\": \"2023-11-07T05:31:56Z\",\n \"options\": {\n \"language\": \"<string>\"\n },\n \"wait_for_completion_ms\": 12500\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://api.scripe.io/v1/posts/generations")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"projectId\": \"proj_a1b2c3d4e5f6g7h8\",\n \"source\": {\n \"type\": \"text\",\n \"text\": \"<string>\"\n },\n \"scheduledFor\": \"2023-11-07T05:31:56Z\",\n \"options\": {\n \"language\": \"<string>\"\n },\n \"wait_for_completion_ms\": 12500\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.scripe.io/v1/posts/generations")
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 \"projectId\": \"proj_a1b2c3d4e5f6g7h8\",\n \"source\": {\n \"type\": \"text\",\n \"text\": \"<string>\"\n },\n \"scheduledFor\": \"2023-11-07T05:31:56Z\",\n \"options\": {\n \"language\": \"<string>\"\n },\n \"wait_for_completion_ms\": 12500\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "job_a1b2c3d4e5f6g7h8",
"type": "POST_GENERATION",
"status": "QUEUED",
"projectId": "<string>",
"startedAt": "2023-11-07T05:31:56Z",
"completedAt": "2023-11-07T05:31:56Z",
"progress": {
"progress": 0.5,
"updatedAt": "2023-11-07T05:31:56Z",
"message": "<string>"
},
"result": {},
"errorCode": "<string>",
"errorMessage": "<string>",
"attemptCount": 1,
"estimatedCompletionMs": 123,
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}{
"error": {
"code": "not_found",
"message": "<string>",
"request_id": "req_a1b2c3d4e5f6",
"docs_url": "<string>",
"details": "<unknown>"
}
}Authorizations
Pass Authorization: Bearer scripe_sk_live_<...> (or
scripe_sk_test_<...> for test keys) on every request. Keys
are scoped to a single workspace and can be revoked from the
Scripe dashboard.
The same header also accepts an OAuth 2.1 access token
(scripe_oat_*); both credentials share one scope vocabulary
and every operation below documents the scope it requires.
An API key can hold every scope named on this surface except
webhooks:manage, which is grantable to OAuth tokens only
today — the webhook-endpoint operations answer
403 scope_missing to every API key. Operations that name no
scope accept any valid token of the workspace.
Headers
Pin the API version. Format YYYY-MM-DD. Omit to receive the
currently rolling default. Unknown versions return 400 version_unsupported.
"2026-08-10"
Opaque string (1–64 chars, [A-Za-z0-9_-]) used to dedup
retried writes. Within 24h of the first request, the same key
- same body returns the original response (
Idempotent-Replayed: true). Same key + different body returns409 idempotency_key_conflict.
Strongly recommended for every write — see
/docs/api/v1/idempotency.
^[A-Za-z0-9_-]{1,64}$Body
"proj_a1b2c3d4e5f6g7h8"
- Option 1
- Option 2
- Option 3
- Option 4
Show child attributes
Show child attributes
Validated when present (must parse, must be in the future),
but it does NOT schedule the generated post — the job always
writes a draft. Put the returned post on the calendar with
PATCH /v1/posts/{postId} once it exists.
Optional steering hints. The worker already loads the
project's tone-of-voice profile, voice samples, content
pillars, and KB — most callers should leave this empty and
put any extra steering into source.text. An idea source
fills contentType from the card's pillar when this omits
it.
Show child attributes
Show child attributes
Soft hint — server polls for up to this many ms before returning. Capped at 25 000 ms. Larger values are silently clamped.
0 <= x <= 25000Response
Job enqueued (or finished, on a sync-wait hit).
Show child attributes
Show child attributes