translations
The methods of pd.translations. Inputs and outputs are described in Conventions; every method can also fail as described in Errors.
Methods
pd.translations.estimate(input, init?)
Estimate a translation
GET /api/articles/{articleId}/translations/estimate
What translating the article would cost, from its current content, next to the workspace's credit wallet and whether the wallet covers it. Needs articles.read. The language is refused (400 INVALID_REQUEST) when the translation would be: not one of the project's languages, or the source's own. Read-only: nothing is reserved or charged until POST /api/articles/{articleId}/translations.
Input
| Name | In | Type | Required | Description |
|---|---|---|---|---|
articleId |
path | string (uuid) |
yes | Id of the source article: the version that is translated from. |
language |
query | string |
yes | Language tag the article would be translated into. Checked as POST /api/articles/{articleId}/translations checks it: it must be one of the project's languages and different from the source article's language (INVALID_REQUEST otherwise). The price depends on the source article's length only. |
init |
init | { signal?: AbortSignal; timeoutMs?: number } |
no | The second argument: signal aborts the call, timeoutMs overrides the client's per-attempt timeout. |
Returns 200 OK
| Field | Type | Required | Description |
|---|---|---|---|
estimate |
object |
yes | What translating the article costs, from its current content. |
estimate.words |
integer |
yes | Words counted in the source article's current content. |
estimate.total |
integer |
yes | Credits the translation costs: one per started 1,000 words of the source. The same amount whatever the target language; reserved when the translation starts. |
wallet |
object |
yes | The workspace's credit wallet now, to compare with estimate.total. |
wallet.balance |
integer |
yes | Every credit the workspace owns, held ones included. |
wallet.reserved |
integer |
yes | Credits held by runs in progress; they leave the balance when those runs settle. |
wallet.available |
integer |
yes | balance less reserved: what a new run can reserve. |
sufficient |
boolean |
yes | Whether wallet.available covers estimate.total. |
Errors 400 invalid input, 401 missing or invalid key, 403 the key's roles lack the permission, 404 not found, 429 rate limited or out of quota. See Errors.
Example
import { PrismDraft } from "@prism-draft/sdk";
const pd = new PrismDraft({ apiKey: process.env.PRISMDRAFT_API_KEY! });
const result = await pd.translations.estimate({
articleId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
language: "example",
});
console.log(result);
pd.translations.create(input, init?)
Translate an article into another of its project's languages
POST /api/articles/{articleId}/translations
Creates the draft version in language, in the source's translation group and starting with the source's categories, and queues a job that translates the content and copies the images. Needs both articles.create and articles.generate. Answers 202 with the QUEUED version and its job; the credits (see GET /api/articles/{articleId}/translations/estimate) are reserved before any model is called, and 402 INSUFFICIENT_CREDITS leaves nothing behind. Repeating an idempotencyKey answers 200 with the original job and reused: true, whatever has happened to it since: job and article are as they are now, so a translation that failed since is returned with its failed job and its draft, not started again, and estimate is null. 409 when the group already has a version in that language (an empty draft left by a failed translation is reused instead) or the source has a generation running; INVALID_REQUEST when the source has no content, the language is the source's own or not one of the project's; 429 QUOTA_EXCEEDED when the copied images would exceed the storage quota. A new version emits an article.created webhook, and an audit entry is written.
Input
| Name | In | Type | Required | Description |
|---|---|---|---|---|
articleId |
path | string (uuid) |
yes | Id of the source article: the version that is translated from. |
body |
body | object |
yes | |
body.language |
body | string |
yes | Language tag to translate into. Must be one of the project's languages and different from the source article's language (INVALID_REQUEST otherwise). |
body.idempotencyKey |
body | string |
no | Client-chosen key, 8 to 200 characters, that makes the request safe to repeat: a second request with the same key answers 200 with the original job instead of starting another. Taken from the Idempotency-Key header when absent here. Without either key a repeat is not recognised as one, but it still cannot start a second translation into a language the group already has: it answers 409 while that version is queued, running or finished. Only when the first translation failed or was cancelled, which leaves an empty draft, does a repeat start a new run, on that draft. |
init |
init | { signal?: AbortSignal; timeoutMs?: number } |
no | The second argument: signal aborts the call, timeoutMs overrides the client's per-attempt timeout. |
Returns 200 OK, 202 Accepted
| Field | Type | Required | Description |
|---|---|---|---|
article |
object |
yes | The version in the target language, a draft in the source's translation group. status is QUEUED on a new request; on a replay it is the version as it is now. Its content is empty until the queued job writes it. |
article.id |
string (uuid) |
yes | Id of the article. |
article.workspaceId |
string (uuid) |
yes | Id of the workspace that owns the article. |
article.projectId |
string (uuid) |
yes | Id of the project the article belongs to. |
article.title |
string |
yes | The article's title, printed above its body. |
article.slug |
string |
yes | The article's address segment, unique among the project's articles of the same language. Renaming an article that has been published keeps its old slug as a redirect. |
article.status |
"DRAFT" | "QUEUED" | "PROCESSING" | "NEEDS_REVIEW" | "CHANGES_REQUESTED" | "APPROVED" | "PUBLISHED" |
yes | Where the article is in its life. DRAFT: being written or edited, and what an unpublished article goes back to. QUEUED and PROCESSING: owned by an AI job (waiting, then running); nothing but the job moves it out. NEEDS_REVIEW: submitted, waiting for a decision. CHANGES_REQUESTED: sent back by a reviewer (reject or request changes). APPROVED: approved and ready to publish. PUBLISHED: published. Only the workflow routes change it, and a move the state machine does not allow answers 409. |
article.documentJson |
object |
yes | The canonical article body as typed blocks. contentHtml and contentMarkdown are rendered from it on every save, so edit this and never them. |
article.documentJson.version |
1 |
yes | Version of the document format. Always 1. |
article.documentJson.blocks |
(object<heading> | object<paragraph> | object<list> | object<quote> | object<image> | object<code> | object<table> | object<divider>)[] |
yes | The article body, top to bottom. Each block's type says which of heading, paragraph, list, quote, image, code, table and divider it is and which other fields it carries. An empty array is an empty article. |
article.documentJson.blocks[]<heading>.id |
string |
yes | Identifier of the block inside its document, 1 to 64 characters. A client picks it; keep it stable across saves, since a comment's targetId and a publish warning's blockId name a block by it. |
article.documentJson.blocks[]<heading>.type |
"heading" |
yes | Block kind: always heading. |
article.documentJson.blocks[]<heading>.level |
1 | 2 | 3 | 4 | 5 | 6 |
yes | Heading rank, 1 (<h1>) to 6 (<h6>). The article's title is its own field and is printed above the body, so generated bodies carry no level-1 heading; one at the very start is part of the lead that stripLead removes. |
article.documentJson.blocks[]<heading>.text |
string |
yes | The heading's words. |
article.documentJson.blocks[]<heading>.format |
"markdown" |
no | Absent: the heading is plain text, shown exactly as written. "markdown": inline Markdown limited to bold, italic, inline code, links (http, https, mailto and relative only), autolinks, escaped characters and character references. |
article.documentJson.blocks[]<paragraph>.id |
string |
yes | Identifier of the block inside its document, 1 to 64 characters. A client picks it; keep it stable across saves, since a comment's targetId and a publish warning's blockId name a block by it. |
article.documentJson.blocks[]<paragraph>.type |
"paragraph" |
yes | Block kind: always paragraph. |
article.documentJson.blocks[]<paragraph>.text |
string |
yes | The paragraph's words. |
article.documentJson.blocks[]<paragraph>.links |
object[] |
no | Links from words of text to other articles, at most 20. Only the first link to each article in the whole document is kept (the rest are dropped on save). Absent: none. Ignored when format is "markdown": write the links in the text instead. |
article.documentJson.blocks[]<paragraph>.links[].text |
string |
yes | The words of the block's text that become the link, 1 to 200 characters. Matched literally, first occurrence only; a link whose words no longer occur in the block is dropped on the next save. |
article.documentJson.blocks[]<paragraph>.links[].articleId |
string (uuid) |
yes | Id of the article the words link to. It is resolved when the article is rendered: the words stay plain text until that article is PUBLISHED in the same project and has an address (its blog page, or the URL its publishing integration reported). |
article.documentJson.blocks[]<paragraph>.format |
"markdown" |
no | Absent: the paragraph is plain text, shown exactly as written. "markdown": inline Markdown limited to bold, italic, inline code, links (http, https, mailto and relative only), autolinks, escaped characters and character references. |
article.documentJson.blocks[]<list>.id |
string |
yes | Identifier of the block inside its document, 1 to 64 characters. A client picks it; keep it stable across saves, since a comment's targetId and a publish warning's blockId name a block by it. |
article.documentJson.blocks[]<list>.type |
"list" |
yes | Block kind: always list. |
article.documentJson.blocks[]<list>.ordered |
boolean |
yes | true: a numbered list. false: a bulleted list. |
article.documentJson.blocks[]<list>.items |
string[] |
yes | The top-level items, as text. A reader that ignores children still sees every top-level item. |
article.documentJson.blocks[]<list>.children |
(object | null)[] |
no | Optional, one entry per item of items (an entry count that differs from items is refused): the level 2 sub-list under that item, or null for an item with none. Lists nest to four levels. |
article.documentJson.blocks[]<list>.children[].ordered |
boolean |
yes | true: a numbered sub-list. false: a bulleted one. Independent of the parent list. |
article.documentJson.blocks[]<list>.children[].items |
string[] |
yes | The sub-list's items, at least one, as text. |
article.documentJson.blocks[]<list>.children[].children |
(object | null)[] |
no | Optional, one entry per item of this sub-list (an entry count that differs from items is refused): the level 3 sub-list under that item, or null for an item with none. Same shape as article.documentJson.blocks[]<list>.children[]: see above. |
article.documentJson.blocks[]<list>.format |
"markdown" |
no | Absent: every item of the list, at every level, is plain text, shown exactly as written. "markdown": inline Markdown limited to bold, italic, inline code, links (http, https, mailto and relative only), autolinks, escaped characters and character references. |
article.documentJson.blocks[]<quote>.id |
string |
yes | Identifier of the block inside its document, 1 to 64 characters. A client picks it; keep it stable across saves, since a comment's targetId and a publish warning's blockId name a block by it. |
article.documentJson.blocks[]<quote>.type |
"quote" |
yes | Block kind: always quote. |
article.documentJson.blocks[]<quote>.text |
string |
yes | The quoted words. |
article.documentJson.blocks[]<quote>.attribution |
string |
no | Who said it, always plain text. Absent: the quote is unattributed. |
article.documentJson.blocks[]<quote>.links |
object[] |
no | Links from words of text to other articles, at most 20. Only the first link to each article in the whole document is kept (the rest are dropped on save). Absent: none. Ignored when format is "markdown": write the links in the text instead. |
article.documentJson.blocks[]<quote>.links[].text |
string |
yes | The words of the block's text that become the link, 1 to 200 characters. Matched literally, first occurrence only; a link whose words no longer occur in the block is dropped on the next save. |
article.documentJson.blocks[]<quote>.links[].articleId |
string (uuid) |
yes | Id of the article the words link to. It is resolved when the article is rendered: the words stay plain text until that article is PUBLISHED in the same project and has an address (its blog page, or the URL its publishing integration reported). |
article.documentJson.blocks[]<quote>.format |
"markdown" |
no | Absent: the quoted text is plain text, shown exactly as written. "markdown": inline Markdown limited to bold, italic, inline code, links (http, https, mailto and relative only), autolinks, escaped characters and character references. |
article.documentJson.blocks[]<image>.id |
string |
yes | Identifier of the block inside its document, 1 to 64 characters. A client picks it; keep it stable across saves, since a comment's targetId and a publish warning's blockId name a block by it. |
article.documentJson.blocks[]<image>.type |
"image" |
yes | Block kind: always image. |
article.documentJson.blocks[]<image>.assetId |
string (uuid) |
yes | Id of the article's asset the block shows (assets[].id of GET /api/articles/{articleId}). The asset's address is resolved when the article is rendered; a block whose asset is missing renders as nothing. The article's hero asset is its cover and cannot be added to the body. |
article.documentJson.blocks[]<image>.altText |
string |
yes | Alternative text for the image. When empty, the asset's own alternative text is used when the article is rendered. |
article.documentJson.blocks[]<image>.caption |
string |
no | Plain-text caption printed under the image. Absent: no caption. |
article.documentJson.blocks[]<code>.id |
string |
yes | Identifier of the block inside its document, 1 to 64 characters. A client picks it; keep it stable across saves, since a comment's targetId and a publish warning's blockId name a block by it. |
article.documentJson.blocks[]<code>.type |
"code" |
yes | Block kind: always code. |
article.documentJson.blocks[]<code>.language |
string |
no | The language of the code (the fence's info string), at most 40 characters, e.g. ts. Renderers keep only the characters A-Z a-z 0-9 _ + # . -. Absent: unspecified. |
article.documentJson.blocks[]<code>.text |
string |
yes | The code, verbatim: never interpreted as Markdown and never translated. |
article.documentJson.blocks[]<table>.id |
string |
yes | Identifier of the block inside its document, 1 to 64 characters. A client picks it; keep it stable across saves, since a comment's targetId and a publish warning's blockId name a block by it. |
article.documentJson.blocks[]<table>.type |
"table" |
yes | Block kind: always table. |
article.documentJson.blocks[]<table>.header |
string[] |
yes | The header row: one cell of text per column, at least one. |
article.documentJson.blocks[]<table>.rows |
string[][] |
yes | The body rows, each an array of cell text with exactly as many cells as header (otherwise refused). May be empty. |
article.documentJson.blocks[]<table>.align |
("left" | "center" | "right" | null)[] |
no | One alignment per column, so as many entries as header has cells (otherwise refused); null leaves a column to the browser's default. Absent: all default. |
article.documentJson.blocks[]<table>.format |
"markdown" |
no | Absent: every cell, header included, is plain text, shown exactly as written. "markdown": inline Markdown limited to bold, italic, inline code, links (http, https, mailto and relative only), autolinks, escaped characters and character references. |
article.documentJson.blocks[]<divider>.id |
string |
yes | Identifier of the block inside its document, 1 to 64 characters. A client picks it; keep it stable across saves, since a comment's targetId and a publish warning's blockId name a block by it. |
article.documentJson.blocks[]<divider>.type |
"divider" |
yes | Block kind: always divider. |
article.contentHtml |
string | null |
yes | The body rendered as HTML from documentJson, with image blocks resolved to their public URLs. Read-only: re-rendered on every document save and again on publish. null before the first render. |
article.contentMarkdown |
string | null |
yes | The body rendered as Markdown from documentJson, with image blocks resolved to their public URLs. Read-only: re-rendered like contentHtml. null before the first render. On GET /api/articles/{articleId}, stripLead=true returns it without the lead. |
article.metaTitle |
string | null |
yes | The SEO title for search results and link previews; null when none is set. |
article.metaDescription |
string | null |
yes | The SEO description for search results and link previews; null when none is set. |
article.targetKeywords |
string[] |
yes | The keywords the article is written to rank for, in the order given. |
article.secondaryKeywords |
string[] |
yes | Supporting keywords to work into the article; empty when none. |
article.primaryLanguage |
string |
yes | Language tag the article is written in, e.g. en or pt-BR; one of the project's languages. |
article.translationGroupId |
string (uuid) |
yes | Shared by every language version of one article, so the versions can be found together. An article with no translations is alone in its group. |
article.generationConfig |
object | null |
yes | The settings an AI generation was started with (topic, tone, length, image style, ...), kept so the article can be rerun. null for an article created without them. |
article.generationConfig.topic |
string |
yes | What the article is about (1 to 500 characters). The outline step plans the article from it, and with primaryKeyword it is the query for web research and for the project's knowledge base. The article's title is not copied from it: the outline's title, written by the model, becomes the title. |
article.generationConfig.prompt |
string |
no | Free-form direction for the writer, up to 5000 characters (angle, points to cover, things to avoid). Sent to the outline step as 'Additional direction'; the section writers follow the outline it produces. |
article.generationConfig.primaryKeyword |
string |
no | The keyword the article targets, up to 200 characters. The outline step is told to use it where it reads naturally, and it joins topic in the research and knowledge-base queries. It is not copied into the article's targetKeywords. |
article.generationConfig.secondaryKeywords |
string[] |
yes | Supporting keywords, up to 25 of 1 to 200 characters. Sent to the outline step, which spreads them over the sections' keywords. Empty by default. Default: []. |
article.generationConfig.audience |
string |
no | Who the article is for, up to 500 characters. Sent to the outline step, to every section writer, to the image-prompt writers and to the knowledge-base query. |
article.generationConfig.tone |
string |
no | The tone to write in, as free text up to 200 characters; the web app offers professional, conversational, authoritative, practical and persuasive. Sent to the outline step as 'Tone'. The section writers read no separate tone: they follow the outline and the brand voice. |
article.generationConfig.language |
string |
yes | Language the article is written in, as a language tag such as en or pt-BR (default en). The outline, section, research and image-prompt steps use it, so the text and the images' alt text come out in it. A run does not change the article's own primaryLanguage. Default: "en". |
article.generationConfig.wordCount |
integer |
yes | Target length of the whole article in words, 200 to 10000 (default 1200). The outline's sections are planned to add up to roughly this. It also sets the text price per started 1,000 words: 2 credits with writingQuality premium, 1 with standard (1200 costs 4 or 2), and the image count when imageCount is null. Default: 1200. |
article.generationConfig.imageStyle |
"photorealistic" | "editorial" | "minimalist-vector" | "3d-render" | "watercolor" | "corporate-tech" | "cinematic" | "illustration" |
yes | Style of the article's images (default editorial). It applies to the cover and the inline images unless the project's imageSettings set a hero.style or inline.style, which take precedence. Values: photorealistic (natural-light documentary photograph, realistic textures, no stylisation), editorial (modern editorial illustration or photograph, clean composition, restrained palette), minimalist-vector (flat vector illustration, few shapes, solid colours, plenty of empty space), 3d-render (soft studio 3D render, smooth matte materials, simple forms), watercolor (loose watercolour painting, soft edges, muted washes), corporate-tech (clean technology visual in cool blues and greys, geometric shapes), cinematic (cinematic still, dramatic lighting, strong atmosphere, wide framing), illustration (hand-drawn illustration, confident linework, warm friendly palette). Default: "editorial". |
article.generationConfig.imageCount |
integer | null |
yes | How many images to make, cover included, 0 to 20. 0 makes none, 1 only the cover, more add one inline image per section up to the number of outline sections. null (the default) derives it from wordCount: 2 under 1,000 words, 3 under 2,000, 4 under 3,000, otherwise 5. Each image delivered costs 1 credit, or 3 when imageQuality is hd; the quote and the reservation count the full number. Default: null. |
article.generationConfig.writingQuality |
"standard" | "premium" |
yes | Which model writes the article (default premium). premium uses the deployment's article model and costs 2 credits per started 1,000 words; standard uses a lighter, cheaper model and costs 1 credit per started 1,000 words. Default: "premium". |
article.generationConfig.imageQuality |
"standard" | "hd" |
yes | Quality of the article's images (default standard). standard costs 1 credit per image; hd asks the image model for its highest quality and costs 3 credits per image, for the run's images and for each regeneration of an image of the article. Default: "standard". |
article.generationConfig.brandVoiceId |
string (uuid) |
no | Id of the brand voice to write in. Absent, or an id that is not one of the workspace's voices, the project's default voice applies, then the workspace's default voice; with neither, no voice is applied. |
article.generationConfig.contentTemplateId |
string (uuid) |
no | Id of the content template to follow: the outline must contain its sections, and the last section ends on its call to action. Only built-in templates and the workspace's own count; any other id, or a deleted template, is ignored without an error. |
article.generationConfig.sourceUrl |
string (uri) |
no | A reference URL for the article. It is stored with the configuration; no generation step reads or fetches it. |
article.generationConfig.researchEnabled |
boolean |
yes | Whether to research and fact-check (default false). Research looks up sources before the outline (needs the deployment's web_research feature); fact checking verifies the finished article's claims (needs fact_checking). Research adds 1 credit and fact checking 3 to the quote, each only when its feature is on, and is charged only if it delivered: research found a source, fact checking checked a claim. Default: false. |
article.generationConfig.reviewOutline |
boolean |
yes | When true the run stops after the outline (default false): the job ends COMPLETED, the article stays DRAFT with the outline stored, and only research, if any, is charged. Read it with GET /api/articles/{articleId}/outline, edit it, then POST /api/articles/{articleId}/outline/approve to write the article. Default: false. |
article.generationConfig.faq |
boolean |
yes | When true (default false) the article ends with a "Frequently asked questions" section of 3 to 5 questions a reader still has after the body, each answered in two or three sentences, in the article's language. It is written after the sections as one more model call, and its words come out of wordCount: the outline is planned for 250 words fewer, so the price does not change. The section is ordinary content (an H2, then an H3 and a paragraph per question) that can be edited like any other. Default: false. |
article.outline |
object | null |
yes | The outline the AI pipeline planned the article from, kept so a writing step can be retried (and, with reviewOutline, the one a person approved). null for an article that was not generated. |
article.outline.title |
string |
yes | The article title, 1 to 300 characters. |
article.outline.slug |
string |
yes | The URL slug: lowercase letters and digits separated by hyphens, up to 120 characters. |
article.outline.metaTitle |
string |
yes | The SEO title, 1 to 70 characters. |
article.outline.metaDescription |
string |
yes | The SEO description, 1 to 200 characters. |
article.outline.sections |
object[] |
yes | The sections in reading order, 1 to 40. |
article.outline.sections[].id |
string |
yes | Identifier of the section inside the outline, 1 to 64 characters. |
article.outline.sections[].heading |
string |
yes | The section's heading, 1 to 300 characters. |
article.outline.sections[].level |
2 | 3 |
yes | Heading rank: 2 for a main section, 3 for a sub-section. |
article.outline.sections[].purpose |
string |
yes | What the section covers, 1 to 1000 characters. |
article.outline.sections[].keywords |
string[] |
yes | The keywords attached to the section, at most 25 of 1 to 120 characters. Empty: none. Default: []. |
article.outline.sections[].estimatedWords |
integer |
yes | The section's length in words, between 20 and 5000. |
article.createdBy |
string | null |
yes | Id of the user who created the article (for an article made with an API key, the key's creator). null when no user is attached or that user has been deleted. |
article.publishedAt |
string (date-time) | null |
yes | The article's publication date: when it was published, or the date given at creation or publish for an imported article. null until then; unpublishing keeps it. |
article.briefId |
string (uuid) | null |
yes | Id of the stored content brief the article was written from; null when none. |
article.publishedUrl |
string | null |
yes | The address the publishing integration reported for the live article, which links from other articles point to. null until a publish reports one, and for a webhook target, which never does. |
article.wordCount |
integer | null |
yes | Words in documentJson, stored with every document write; null for an article not counted since the count was added, until the backfill reaches it. |
article.createdAt |
string (date-time) |
yes | When the article was created. |
article.updatedAt |
string (date-time) |
yes | When the article last changed (a save, a status move, a re-render). It is what expectedUpdatedAt is compared with on PATCH /api/articles/{articleId}. |
job |
object |
yes | The translation job (kind translation) that writes the version in the background. On a replay, the job the idempotency key started first. |
job.id |
string (uuid) |
yes | Id of the run. Cancelling and settling credits are tracked against it. |
job.articleId |
string (uuid) |
yes | Id of the article the run works on. |
job.workspaceId |
string (uuid) |
yes | Id of the workspace that owns the article. |
job.projectId |
string (uuid) |
yes | Id of the project the article belongs to. |
job.status |
"QUEUED" | "TRANSLATING" | "VALIDATING" | "RESEARCHING" | "OUTLINING" | "WRITING" | "GENERATING_IMAGE_PROMPTS" | "GENERATING_IMAGES" | "PROCESSING_MEDIA" | "FINALIZING" | "COMPLETED" | "FAILED" | "CANCELLED" |
yes | Where the run is. QUEUED: accepted, not started yet. VALIDATING, RESEARCHING, OUTLINING, WRITING, GENERATING_IMAGE_PROMPTS, GENERATING_IMAGES, PROCESSING_MEDIA, FINALIZING: the pipeline is in that step, in this order (research only when requested; the outline step is skipped when resuming an approved outline). TRANSLATING: a translation run is working. COMPLETED, FAILED and CANCELLED are final. |
job.kind |
"generation" | "translation" |
yes | generation writes an article from its configuration; translation translates an article into another language. |
job.currentStep |
"validate" | "research" | "outline" | "write" | "image-prompts" | "images" | "media-processing" | "translate" | "finalize" | null |
yes | The step the run last entered; null while it is still QUEUED. |
job.progress |
integer |
yes | Percent of the run completed, 0 to 100. It moves to the step's value on entering each step and is 100 when the run is COMPLETED; a failed or cancelled run keeps the value it reached. |
job.idempotencyKey |
string |
yes | The key the run was started with: the one the client sent, or one the server generated. Unique across all runs; a request that repeats it gets this run back. |
job.estimatedCredits |
integer |
yes | Credits quoted when the run was started, the most it can cost: the full quote for POST /api/articles/{articleId}/generate, the writing leg's share for POST /api/articles/{articleId}/outline/approve. |
job.reservedCredits |
integer |
yes | Credits held against the wallet when the run was queued, equal to estimatedCredits. The hold ends when the run settles, but this value is not reset; read consumedCredits for what was charged. |
job.consumedCredits |
integer |
yes | Credits charged for the work delivered, set when the run settles and never above reservedCredits; 0 until then, and 0 for a run that failed before the article was saved or was cancelled. |
job.errorCode |
string | null |
yes | GENERATION_FAILED or TRANSLATION_FAILED when status is FAILED; otherwise null. |
job.errorMessage |
string | null |
yes | The message of the error that failed the run; null unless status is FAILED. |
job.createdAt |
string (date-time) |
yes | When the run was accepted, ISO 8601. |
estimate |
object | null |
yes | What this request reserved: the words counted and the credits. Null on a replay (reused true), which reserves nothing. |
estimate.words |
integer |
yes | Words counted in the source article's current content. |
estimate.total |
integer |
yes | Credits the translation costs: one per started 1,000 words of the source. The same amount whatever the target language; reserved when the translation starts. |
reused |
boolean |
yes | True when the idempotency key had already started this job: the answer is then the original job, with status 200 instead of 202. |
Errors 400 invalid input, 401 missing or invalid key, 403 the key's roles lack the permission, 404 not found, 429 rate limited or out of quota. See Errors.
Example
import { PrismDraft } from "@prism-draft/sdk";
const pd = new PrismDraft({ apiKey: process.env.PRISMDRAFT_API_KEY! });
const result = await pd.translations.create({
articleId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
body: {
language: "example",
},
});
console.log(result);