usage
The methods of pd.usage. Inputs and outputs are described in Conventions; every method can also fail as described in Errors.
Methods
pd.usage.listTransactions(input, init?)
The credit ledger, newest first
GET /api/workspaces/{workspaceId}/transactions
Requires credits.read. The credit ledger is append-only: every credit and debit is a row, and rows are never updated or deleted. amount is signed against the available credits and type says what the row records. Returns up to limit rows, at most 200, and has no offset.
Input
| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceId |
path | string (uuid) |
yes | Id of the workspace the request works in. The caller must be a member of it, or hold an API key issued by it. For anyone else, an unknown id and an id they do not belong to both answer 404 RESOURCE_NOT_FOUND, so membership cannot be probed. |
limit |
query | integer |
no | Most ledger rows to return, newest first. From 1 to 200, default 50. The route has no offset, so rows older than the newest limit cannot be reached. Default: 50. |
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 |
|---|---|---|---|
transactions |
object[] |
yes | Ledger rows, newest first, up to limit. |
transactions[].id |
string (uuid) |
yes | Id of the ledger row. |
transactions[].workspaceId |
string (uuid) |
yes | Id of the workspace whose wallet the row belongs to. |
transactions[].walletId |
string (uuid) |
yes | Id of the credit wallet the row changed. |
transactions[].type |
"purchase" | "consumption" | "refund" | "reservation" | "reservation_release" | "reservation_capture" | "manual_adjustment" | "expiration" | "signup_grant" | "subscription_grant" | "platform_gift" |
yes | What the ledger row records, with the sign of amount. purchase (+): a credit pack paid for, added when Stripe confirms the payment. consumption (-): a direct debit for work with no prior reservation. refund (-): credits taken back after Stripe refunded a pack purchase; metadata.shortfall holds what had already been spent and could not be reclaimed. reservation (-): credits earmarked for a running operation; the total balance does not change. reservation_release (+): an earmark lifted, so the credits are available again; also written, for the full hold, just before a reservation_capture. reservation_capture (-): the actual charge for the work, never more than the hold. manual_adjustment (+ or -): an Owner's correction, with metadata.reason. expiration: positive when a stale reservation is lifted, negative when plan credits expire at renewal or when the subscription ends. signup_grant (+): the one-time grant at sign-up. subscription_grant (+): the plan credits for one paid subscription invoice. platform_gift (+): credits the PrismDraft team gave the workspace, with metadata.reason. |
transactions[].amount |
integer |
yes | Signed change to the available credits: positive when credits were added or made available again, negative for debits and new reservations. Summing amount over the ledger gives the available credits. |
transactions[].balanceAfter |
integer |
yes | The wallet's total balance after this row, not its available credits: a reservation row leaves it unchanged. |
transactions[].referenceType |
string | null |
yes | What referenceId points at, e.g. credit_reservation, article_generation_job, article_asset, stripe_checkout_session, subscription_invoice or plan_credits; null when the row refers to nothing, as with a manual adjustment. |
transactions[].referenceId |
string | null |
yes | Id of the record named by referenceType; null when there is none. |
transactions[].stripeEventId |
string | null |
yes | Id of the Stripe event that caused the row (evt_…), set on purchases, refunds and subscription grants; unique, so a replayed event cannot credit twice. Null otherwise. |
transactions[].metadata |
unknown |
yes | A JSON object the writer attached, e.g. reason on an adjustment; {} when none. |
transactions[].createdBy |
string | null |
yes | Id of the user who caused the row; null for system and Stripe movements and for API keys. |
transactions[].createdAt |
string (date-time) |
yes | When the row was written; rows are never updated afterwards. |
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.usage.listTransactions({
workspaceId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
});
console.log(result);
pd.usage.get(input, init?)
Usage records, filterable by window, project, user, operation and provider
GET /api/workspaces/{workspaceId}/usage
Requires analytics.read. Returns two views of the usage records that match the filters: summary groups them by operation type, provider and model, and records lists the newest ones up to limit. Usage records say what providers were asked to do, with an estimated provider cost in USD micros; they are kept apart from the credits charged. In summary, credits and estimatedProviderCostMicros are bigint sums and arrive as decimal strings. costKnown false means the model has no known rate, so a cost of 0 is absence of data, not a free call.
Input
| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceId |
path | string (uuid) |
yes | Id of the workspace the request works in. The caller must be a member of it, or hold an API key issued by it. For anyone else, an unknown id and an id they do not belong to both answer 404 RESOURCE_NOT_FOUND, so membership cannot be probed. |
from |
query | string (date-time) |
no | Start of the window, inclusive: a UTC ISO 8601 datetime such as 2026-10-01T00:00:00Z. Omit for no lower bound. |
to |
query | string (date-time) |
no | End of the window, inclusive: a UTC ISO 8601 datetime. Omit for no upper bound. |
projectId |
query | string (uuid) |
no | Only records written for this project. Omit for every project. |
userId |
query | string |
no | Only records of operations started by this user (a user id). Omit for every user. |
type |
query | "article_generation" | "article_translation" | "image_generation" | "image_regeneration" | "ai_edit" | "research" | "fact_check" | "embedding" |
no | Only records of this operation type (see type on a record). Accepts every type except site_analysis. Omit for all types. |
provider |
query | string |
no | Only records served by this provider, matched exactly, e.g. openai. Omit for all providers. |
limit |
query | integer |
no | Most records to return in records, newest first. From 1 to 200, default 50. summary is not limited by it. Default: 50. |
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 |
|---|---|---|---|
summary |
object[] |
yes | Totals per operation type, provider and model over every record that matches the filters; not limited by limit. |
summary[].type |
"article_generation" | "article_translation" | "image_generation" | "image_regeneration" | "ai_edit" | "research" | "fact_check" | "embedding" | "site_analysis" |
yes | The operation that was paid for. article_generation: writing an article or its outline. article_translation: translating an article. image_generation: images made with an article. image_regeneration: one image regenerated on its own. ai_edit: an AI edit or suggestion, including category and idea suggestions. research: web research searches. fact_check: fact-checking an article's claims. embedding: embedding a knowledge source for search. site_analysis: analysing a website for a project. |
summary[].provider |
string |
yes | Name of the provider the group's calls went to. |
summary[].model |
string | null |
yes | Model the group's calls used; null for records with no model. |
summary[].operations |
integer |
yes | Number of usage records in the group. |
summary[].inputTokens |
integer |
yes | Sum of prompt tokens over the group. |
summary[].outputTokens |
integer |
yes | Sum of output tokens over the group. |
summary[].images |
integer |
yes | Sum of images generated over the group. |
summary[].credits |
integer | string |
yes | Credits charged over the group. A bigint sum: the wire carries a decimal string, e.g. "3", so parse it before doing arithmetic. |
summary[].estimatedProviderCostMicros |
integer | string |
yes | USD times 1,000,000, a bigint sum: the wire carries a decimal string, e.g. "1500". |
summary[].costKnown |
boolean |
yes | False when the model has no known rate: a cost of 0 is then absence of data. |
records |
object[] |
yes | The most recent matching usage records, newest first, at most limit (default 50). No offset: older ones are reached by narrowing from and to. |
records[].id |
string (uuid) |
yes | Id of the usage record. |
records[].workspaceId |
string (uuid) |
yes | Id of the workspace that paid for the operation. |
records[].projectId |
string (uuid) | null |
yes | Id of the project the operation ran in; null when it belongs to none. |
records[].userId |
string | null |
yes | Id of the user who triggered the operation; null when it was not started by a user or the user was deleted. |
records[].type |
"article_generation" | "article_translation" | "image_generation" | "image_regeneration" | "ai_edit" | "research" | "fact_check" | "embedding" | "site_analysis" |
yes | The operation that was paid for. article_generation: writing an article or its outline. article_translation: translating an article. image_generation: images made with an article. image_regeneration: one image regenerated on its own. ai_edit: an AI edit or suggestion, including category and idea suggestions. research: web research searches. fact_check: fact-checking an article's claims. embedding: embedding a knowledge source for search. site_analysis: analysing a website for a project. |
records[].provider |
string |
yes | Name of the provider that served the call, e.g. openai. |
records[].model |
string | null |
yes | Model that served the call; null when none applies. |
records[].quantity |
integer |
yes | How much the operation used, counted in unit. For article_generation it is the number of articles written (0 for a run that produced none, such as an outline-only leg). |
records[].unit |
"tokens" | "images" | "requests" | "bytes" |
yes | What quantity counts: model tokens, generated images, provider requests, or bytes. |
records[].inputTokens |
integer |
yes | Prompt tokens sent to the model; 0 for calls that are not token-priced. |
records[].outputTokens |
integer |
yes | Tokens the model returned; 0 for calls that are not token-priced. |
records[].imageCount |
integer |
yes | Images generated by the call; 0 for other operations. |
records[].durationMs |
integer |
yes | Wall-clock duration of the call in milliseconds; 0 when it was not measured. |
records[].estimatedProviderCostMicros |
integer |
yes | Estimated cost the provider charged, in millionths of a US dollar (USD times 1,000,000). 0 for a model with no known rate, which means unknown rather than free. Kept apart from credits, which is what the customer paid. |
records[].credits |
integer |
yes | Credits this operation cost the workspace; 0 when it was free of charge. |
records[].referenceType |
string | null |
yes | What referenceId points at, e.g. article_generation_job; null when nothing. |
records[].referenceId |
string | null |
yes | Id of the record named by referenceType; null when there is none. |
records[].metadata |
unknown |
yes | A JSON object the writer attached, e.g. leg: "outline"; {} when none. |
records[].createdAt |
string (date-time) |
yes | When the operation was recorded. |
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.usage.get({
workspaceId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
});
console.log(result);
pd.usage.listPayments(input, init?)
Checkout and payment history
GET /api/workspaces/{workspaceId}/payments
Requires billing.read. Lists the workspace's credit-pack checkouts, newest first, at most 50. Pending, expired and failed checkouts are listed too; only completed ones added credits. Subscription payments are not here: they are the invoices of GET /api/workspaces/{workspaceId}/subscription. Card details and Stripe customer identifiers are never returned.
Input
| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceId |
path | string (uuid) |
yes | Id of the workspace the request works in. The caller must be a member of it, or hold an API key issued by it. For anyone else, an unknown id and an id they do not belong to both answer 404 RESOURCE_NOT_FOUND, so membership cannot be probed. |
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 |
|---|---|---|---|
payments |
object[] |
yes | Credit-pack checkouts, newest first, at most 50, whatever their status. Subscription payments appear as invoices in the subscription read. |
payments[].id |
string (uuid) |
yes | Id of the checkout session record. |
payments[].packageName |
string | null |
yes | Name of the credit pack that was bought; null if the pack no longer exists. |
payments[].priceCents |
integer | null |
yes | The pack's current price in the smallest unit of currency; null if the pack no longer exists. |
payments[].currency |
string | null |
yes | Lower-case ISO 4217 code of the pack's price; null if the pack no longer exists. |
payments[].creditAmount |
integer |
yes | Credits the purchase adds, fixed when the checkout was opened. |
payments[].status |
"pending" | "completed" | "expired" | "failed" |
yes | pending: the Stripe Checkout session was opened and no outcome has arrived. completed: Stripe confirmed the payment and the credits were added. expired: the session lapsed unpaid. failed: the payment did not go through. |
payments[].createdAt |
string (date-time) |
yes | When the checkout was opened. |
payments[].completedAt |
string (date-time) | null |
yes | When Stripe confirmed the payment; null until then. |
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.usage.listPayments({
workspaceId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
});
console.log(result);
pd.usage.listQuotas(input, init?)
Quota limits and current consumption
GET /api/workspaces/{workspaceId}/quotas
Requires billing.read. Lists the quotas configured for the workspace with what has been used against each. Quotas are entitlements kept apart from the credit balance: a workspace holding credits is still refused with 429 QUOTA_EXCEEDED once a quota is used up. A metric with no entry is unlimited. The limits a plan sets (users, projects, ai_operations) are listed here too. Entries do not say which period they count over.
Input
| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceId |
path | string (uuid) |
yes | Id of the workspace the request works in. The caller must be a member of it, or hold an API key issued by it. For anyone else, an unknown id and an id they do not belong to both answer 404 RESOURCE_NOT_FOUND, so membership cannot be probed. |
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 |
|---|---|---|---|
quotas |
object[] |
yes | One entry per configured quota. A metric with no entry has no limit. The period a quota counts over (month or total) is not part of the entry. |
quotas[].metric |
"articles" | "images" | "ai_operations" | "storage_bytes" | "users" | "projects" | "api_requests" |
yes | What the quota limits. articles: articles generated. images: images generated, with an article or on their own. ai_operations: AI calls counted against the plan's monthly allowance (set by the plan): AI edits, idea, brief, category, internal-link and social-post generation, and generation runs that stop at the outline for review. storage_bytes: bytes of stored article assets. users: members of the workspace (set by the plan). projects: projects in the workspace (set by the plan). api_requests: requests authenticated with the workspace's API keys. |
quotas[].limit |
integer |
yes | The configured limit, in the metric's own unit (a count; bytes for storage_bytes). 0 blocks the metric entirely. |
quotas[].used |
integer |
yes | Consumption counted against the limit now, in the same unit. |
quotas[].remaining |
integer |
yes | limit less used, never below 0. |
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.usage.listQuotas({
workspaceId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
});
console.log(result);
pd.usage.setQuota(input, init?)
Set or clear a quota
PUT /api/workspaces/{workspaceId}/quotas
Requires billing.manage. Sets the limit of one metric for a period, or removes it when limitValue is null, which leaves the metric unlimited. users, projects and ai_operations belong to the workspace's plan, which rewrites them on every subscription event, so they are refused with 400. Records a billing.quota_changed audit entry and returns the full quota list, as the read route does.
Input
| Name | In | Type | Required | Description |
|---|---|---|---|---|
workspaceId |
path | string (uuid) |
yes | Id of the workspace the request works in. The caller must be a member of it, or hold an API key issued by it. For anyone else, an unknown id and an id they do not belong to both answer 404 RESOURCE_NOT_FOUND, so membership cannot be probed. |
body |
body | object |
yes | |
body.metric |
body | "articles" | "images" | "ai_operations" | "storage_bytes" | "users" | "projects" | "api_requests" |
yes | What to limit: articles, images, storage_bytes or api_requests. users, projects and ai_operations are set by the workspace's plan and are refused with 400. |
body.period |
body | "month" | "total" |
no | What the quota counts over: month since the start of the current UTC month, or total over all time. Defaults to month. storage_bytes is always counted as stored now, whatever the period. Default: "month". |
body.limitValue |
body | integer | null |
yes | The limit, in the metric's unit (a count; bytes for storage_bytes). 0 blocks the metric entirely. Null removes the quota for this metric and period, which leaves it unlimited. |
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 |
|---|---|---|---|
quotas |
object[] |
yes | One entry per configured quota. A metric with no entry has no limit. The period a quota counts over (month or total) is not part of the entry. |
quotas[].metric |
"articles" | "images" | "ai_operations" | "storage_bytes" | "users" | "projects" | "api_requests" |
yes | What the quota limits. articles: articles generated. images: images generated, with an article or on their own. ai_operations: AI calls counted against the plan's monthly allowance (set by the plan): AI edits, idea, brief, category, internal-link and social-post generation, and generation runs that stop at the outline for review. storage_bytes: bytes of stored article assets. users: members of the workspace (set by the plan). projects: projects in the workspace (set by the plan). api_requests: requests authenticated with the workspace's API keys. |
quotas[].limit |
integer |
yes | The configured limit, in the metric's own unit (a count; bytes for storage_bytes). 0 blocks the metric entirely. |
quotas[].used |
integer |
yes | Consumption counted against the limit now, in the same unit. |
quotas[].remaining |
integer |
yes | limit less used, never below 0. |
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.usage.setQuota({
workspaceId: "3f0c5a1e-8b2d-4c6e-9a7f-1d2e3f4a5b6c",
body: {
metric: "articles",
limitValue: 1,
},
});
console.log(result);