Credits
USD-denominated compute credits — balance, ledger history, budget/overage, and pre-flight cost estimation. Gate paid operations to avoid mid-run PaymentRequiredError.
Pictograph bills paid operations against a USD-denominated compute-credit wallet, one per organization. Free actions (uploads, exports, search, manual annotation) cost nothing.
Every example below shows the Python SDK call and the equivalent raw REST
request. The REST examples authenticate with an X-API-Key header; set
PICTOGRAPH_API_KEY in your shell to copy-and-run them.
Units. Compute credits are carried on the wire as integer micro-USD
(µUSD): 1 USD = 1,000,000 µUSD. Every *_micro_usd field is an int
count of µUSD. The SDK models also expose *_usd convenience properties that
divide by 1,000,000 to give a float dollar amount for display.
Allowance + pay-as-you-go. Each plan includes a monthly compute allowance (Free includes $5, Core $29, Pro $50, Team $100). The allowance renews at the start of every billing period and does not roll over. Beyond the included allowance, an org with a saved card can turn on pay-as-you-go in the app — either auto-recharge (top up the compute balance from the card when it runs low, by an amount you choose) or buying credits on demand. Pay-as-you-go is available on every plan including Free, and prepaid compute carries over between periods. With pay-as-you-go off, an org hard-stops at its included allowance (the Free tier stops at its included $5). An optional monthly Budget cap bounds total spend beyond the allowance — the fields below expose the allowance, the spend so far, and any Budget cap.
from pictograph import Client
client = Client() # reads PICTOGRAPH_API_KEY
balance
Current wallet state + the last 20 ledger entries.
balance = client.credits.balance()
# USD convenience properties for display
print(f"{balance.remaining_usd:.2f} of {balance.allowance_usd:.2f} included left")
print(f"Spent this period: ${balance.spend_usd:.2f}")
print(f"Overage so far: ${balance.overage_usd:.2f} (budget cap ${balance.budget_usd:.2f})")
print("Allowance resets:", balance.credits_reset_at)
for entry in balance.recent_history:
print(entry.created_at, entry.operation, entry.amount) # amount is signed µUSD
curl -s "https://api.pictograph.io/api/v1/developer/credits/balance" \
-H "X-API-Key: $PICTOGRAPH_API_KEY"
Returns CreditBalance. The authoritative fields are integer micro-USD:
| Field | Meaning |
|---|---|
included_allowance_micro_usd | Monthly included compute allowance (µUSD). |
included_remaining_micro_usd | Included allowance left this period (µUSD). |
budget_micro_usd | Overage budget cap beyond the allowance (µUSD). Equals the allowance when pay-as-you-go is off. |
period_spend_micro_usd | Total compute spend this period (µUSD). |
period_overage_micro_usd | Spend beyond the included allowance this period (µUSD). |
budget_remaining_micro_usd | Remaining overage budget under the cap (µUSD). |
period_start | Start of the current billing period. |
credits_reset_at | When the monthly allowance resets next. |
Each has a matching *_usd float property (.remaining_usd, .allowance_usd,
.budget_usd, .overage_usd, .spend_usd, .budget_remaining_usd).
The whole-dollar integer fields (
credits_remaining,credits_monthly_allowance) are deprecated — kept for backward compatibility, default0. Read the*_micro_usdfields /*_usdproperties instead.
history
Page through the ledger (newest first).
| Arg | Type | Default | Notes |
|---|---|---|---|
limit | int | 50 | Page size (backend cap: 100) |
offset | int | 0 | Page offset |
entries = client.credits.history(limit=50, offset=0)
for e in entries:
direction = "debit" if e.amount < 0 else "credit"
print(e.created_at, direction, abs(e.amount), "µUSD", e.operation)
curl -s "https://api.pictograph.io/api/v1/developer/credits/history?limit=50&offset=0" \
-H "X-API-Key: $PICTOGRAPH_API_KEY"
Each entry’s amount and balance_after are signed micro-USD integers.
Sign convention: amount < 0 = debit (operation consumed credit),
amount > 0 = credit / refund (top-up, monthly reset, training-overcharge
refund). balance_after is the org’s spendable balance (µUSD) immediately
after the entry posted.
usage_by_operation
Per-operation compute spend (µUSD, debits only), aggregated in the database over a time window. Use this for a “where did my credits go” breakdown without paging the raw ledger.
| Arg | Type | Default | Notes |
|---|---|---|---|
range | str | "month" | One of day / week / month / all |
usage = client.credits.usage_by_operation(range="month")
print(f"{usage.total_events} events, ${usage.total_micro_usd / 1e6:.2f} total")
for op in usage.operations:
print(f"{op.operation}: ${op.total_usd:.2f} over {op.event_count} events")
curl -s "https://api.pictograph.io/api/v1/developer/credits/usage-by-operation?range=month" \
-H "X-API-Key: $PICTOGRAPH_API_KEY"
Returns UsageByOperation with operations (list[OperationUsage], each with
operation, total_micro_usd / total_usd, and event_count) plus the window
totals total_micro_usd and total_events.
iter
Auto-paging iterator over the entire ledger.
for entry in client.credits.iter(page_size=100):
print(entry.balance_after, entry.operation) # balance_after in µUSD
# Page manually with limit + offset until fewer than `limit` rows return.
curl -s "https://api.pictograph.io/api/v1/developer/credits/history?limit=100&offset=0" \
-H "X-API-Key: $PICTOGRAPH_API_KEY"
Returns OffsetPager[CreditLedgerEntry].
estimate
Pre-flight cost check before invoking a paid operation. Prices are set in
USD — for example, training is billed per GPU-minute and image
generation/editing per image — and estimate returns the live price for
the operation, so you never need to hard-code costs.
| Arg | Type | Default | Notes |
|---|---|---|---|
operation | str | required | Operation slug (e.g. "training_a10g") |
quantity | int | 1 | Number of units to price |
estimate = client.credits.estimate("training_a10g", quantity=30)
print(f"${estimate.per_unit_usd:.4f} per {estimate.unit}")
print(f"Total: ${estimate.total_usd:.2f} for {estimate.quantity} {estimate.unit}(s)")
print("Sufficient:", estimate.sufficient)
curl -s "https://api.pictograph.io/api/v1/developer/credits/estimate?operation=training_a10g&quantity=30" \
-H "X-API-Key: $PICTOGRAPH_API_KEY"
Returns CreditEstimate:
| Field | Meaning |
|---|---|
operation | The operation slug you passed. |
unit | Unit of measure — "minute", "image", "run", etc. |
quantity | Number of units priced. |
micro_usd_per_unit | Per-unit price in micro-USD (µUSD). |
total_micro_usd | micro_usd_per_unit × quantity, in µUSD. |
remaining_micro_usd | The org’s spendable compute credit when the estimate ran (µUSD). |
sufficient | True if the org can currently afford total_micro_usd. |
total_usd / per_unit_usd / remaining_usd are the float-dollar
convenience properties.
Common operation slugs: training_a10g, training_a100, training_h100,
sam3_auto_annotation, inference_t4, image_generate_imagen_fast,
image_edit_gemini_flash. The full, authoritative price list lives
server-side — call estimate for the current per-unit price rather than
assuming a fixed cost.
sufficient=True is not a guarantee — another caller may drain the wallet
between the estimate and the actual call. The authoritative answer is the
operation’s own PaymentRequiredError.
Tier-gated operations.
image_generate_*,image_edit_*, batch auto-annotation, model training, and model deployments require the Core plan or higher. SAM3 auto-annotation is available on every tier. On a Free-tier org the gated endpoints return403 tier_restrictedbefore any credit is debited.
Gating in workflows
full_pipeline already gates on wallet balance before kicking off
paid phases:
from pictograph.pipelines import full_pipeline
report = full_pipeline(
client,
dataset_name="…", folder="…", classes=…, pipeline="yolox",
min_credits=1, # skip annotate + train if wallet is short
)
if report.credit_skip_reason:
print(report.credit_skip_reason)
min_credits=None disables the check.
PaymentRequiredError details
from pictograph.exceptions import PaymentRequiredError
try:
client.training.create(dataset_name, export_name, pipeline_type="yolox")
except PaymentRequiredError as e:
# e.credit_cost / e.credits_remaining are integer µUSD (e.unit == "micro_usd")
print(f"Need ${e.credit_cost / 1e6:.2f}, have ${e.credits_remaining / 1e6:.2f}")
print(f"Top up at: {e.upgrade_url}")
A PaymentRequiredError is raised when an operation’s cost exceeds the
org’s spendable compute credit — that is, the included allowance plus any
remaining overage budget. Raising the plan or the Budget cap clears it.
Refunds
The training pipeline auto-refunds unused GPU minutes when:
- A run is cancelled mid-training.
- A run failed before consuming the full
timeoutbudget.
Refunds appear as positive ledger entries (operation training_refund_<gpu>).
No SDK call required.
Common errors
| Status | Exception | Cause |
|---|---|---|
| 422 | ValidationError | operation slug is not a known credit operation |
| 402 | PaymentRequiredError | (raised by the operation being estimated, not by estimate itself) |