# Credits (/docs/credits) How credit billing works. Tiers, the welcome bonus, free cache hits, automatic refunds, and monitor costs Every request costs credits based on the endpoint's tier. New accounts get 100 free credits, cache hits cost nothing, and a request that fails on our side or upstream is refunded automatically. Billing is pay as you go: there is no subscription, and credits do not expire. ## What does a request cost? [Endpoint pricing](/docs/endpoint-pricing.md) publishes the exact figure for every individual endpoint. ### Endpoints that are not on the ladder Composite and metered endpoints carry their own price and can bill well above the premium tier. | Endpoint | Cost | | ------------------------------------------------------ | ----------------------------------------------------------------------------------------- | | `/v1/prism/brand-mentions` | Flat 50 credits | | `/v1/prism/leads` | Flat 50 credits | | `/v1/prism/ai-visibility` | 2 to 1,605 credits, depending on how many prompts, runs, and engines you ask for | | `/v1/prism/comments` | Metered per comment page for most sources, but a flat 5 credits for an Instagram post URL | | `POST /v1/youtube/videos`, `POST /v1/youtube/channels` | 5 credits per 50 ids | Check [Endpoint pricing](/docs/endpoint-pricing.md) for the exact figure or range rather than assuming a tier. A metered endpoint deducts its upper bound when the request is dispatched, then refunds the difference the moment the real cost is known. `credits_used` on a metered call is often lower than the deduction you saw. A few of them also carry per-input rules that a published range cannot express, so read the endpoint's own page before you budget for it. ## Web monitors are the one charge that repeats Every price above is per request. You call, you pay once, and nothing else happens. Web monitors are the exception. Creating a monitor costs 0 credits, but a monitor is a standing instruction, and every scheduled check it runs afterwards is billed. **Each check costs the endpoint's own upstream cost, plus 1 credit for orchestration.** A monitor watching a page that costs 1 credit to scrape bills 2 credits per check. That repeats on the `cadence_minutes` you set, as tight as every 5 minutes or any whole number of hours up to 1440 (daily), and it keeps repeating until you pause or delete the monitor. Nobody has to be logged in, and no further API calls are needed on your side. | Cadence | Checks per day | Checks per month | Monthly cost at 2 credits/check | | --------------- | -------------- | ---------------- | ------------------------------- | | Every 5 minutes | 288 | ~8,640 | ~17,280 credits | | Every hour | 24 | ~720 | ~1,440 credits | | Every 24 hours | 1 | ~30 | ~60 credits | A 5-minute monitor on a 1-credit page drains the 100-credit welcome bonus in under four hours. Use that cadence only when the job needs a check that often. The create response tells you what a single check costs. `credits_booked` is the upstream cost, so your real monthly figure is `(credits_booked + 1) × checks per month`. List what is currently running with `GET /v1/web/monitors`. If your balance runs out, checks are not queued and nothing goes negative. The check is recorded as `skipped` at 0 credits, the schedule moves on to the next slot, and the monitor stays active, so it resumes on its own once you top up. ## Welcome bonus Every new account receives **100 free credits** on signup, enough to try every standard endpoint without attaching a payment method. The bonus appears in your transaction history as a `bonus` entry. ## How do I check my balance? Three ways, depending on context. 1. **On the response.** API responses normally include both body `credits_remaining` and an `X-Credits-Remaining` header. A cache hit does not read your balance, so its body value is `null` with a `credits_remaining_note`, and the header is omitted. The same happens when an idempotency replay has a transient balance lookup failure. 2. **From the meta endpoint.** `GET /v1/credits/balance` costs 0 credits and takes API-key auth. It returns the balance, the number of recent deductions, and a top-up offer: how many days the balance lasts, the pack that fits, a link to buy it and the auto-recharge state. For a key with a credit limit, `GET /v1/keys/current` (also 0 credits) adds what that key may still spend, and every response made with it carries `X-Key-Credits-Remaining`. 3. **In the dashboard.** The Usage and Activity Logs pages show balance, history, and per-endpoint breakdowns. ```json title="Response" { "success": true, "platform": "meta", "endpoint": "/v1/credits/balance", "data": { "balance": 1332, "recent_deductions": 128, "runway": { "window_days": 14, "credits_per_day": 666, "days_left": 2 }, "recommended_pack": { "id": "growth", "name": "Growth", "credits": 20000, "price_gbp": 49, "price_display": "£49", "days_at_current_burn": 30, "credits_per_day": 666, "burn_window_days": 14 }, "top_up_url": "https://www.socialcrawl.dev/dashboard/billing/payments?pack=growth", "checkout_url": "https://www.socialcrawl.dev/dashboard/billing/checkout?token=...", "auto_recharge": { "enabled": false, "armed": false, "threshold_credits": null, "pack_id": null, "has_card": false, "disabled_reason": null, "blocked_reason": null, "setup_url": "https://www.socialcrawl.dev/dashboard/billing/payments?autorecharge=enable#auto-recharge" } }, "credits_used": 0, "credits_remaining": 1332, "request_id": "req-abc123", "cached": false } ``` `runway.days_left` is the balance divided by the credits a day the account used over the last 14 days, rounded down. It is `null` when there is no recent use to measure. `recommended_pack`, `top_up_url`, `checkout_url` and `auto_recharge` have the same meaning as the fields of the same name on an [`INSUFFICIENT_CREDITS` error](/docs/errors.md#insufficient-credits). `auto_recharge.blocked_reason` is `monthly_cap`, `retry_after_failure` or `needs_reconfirm` when an armed auto-recharge cannot top up right now, and `null` otherwise. If the offer cannot be read in time, the response leaves out `runway`, `recommended_pack`, `top_up_url`, `checkout_url` and `auto_recharge` and still returns `balance` and `recent_deductions`, so treat all five as optional. ### Warn before you run out An agent or script that polls the balance can tell its owner before a call is refused. When `runway.days_left` is under 3, show the owner `checkout_url`. It opens checkout for `recommended_pack` once the owner is logged in, and nothing is charged until they pay. Polling stays free and the offer is cached for 5 minutes, so a frequent poll costs no extra credits. ## Are cache hits free? Yes. A response served from cache (`"cached": true`, `X-Cache: HIT`) costs **0 credits**. No transaction row is written and your balance is unchanged. We already paid the upstream cost when we fetched the original, so charging you again for the same data would be double-billing. Caching is on by default for cache-enabled endpoints and is the single biggest lever for keeping your bill down. See [Caching](/docs/caching.md) for the freshness window per data type, the shared-across-account model, and how to force a guaranteed-live fetch. Endpoints marked uncached run and bill on every request. ## When are credits refunded? Credits are refunded automatically when a paid request cannot complete successfully. | Scenario | Status | Refund | | --------------------------------------------------------- | ------------------------- | ------------------- | | Upstream platform error | 502 `UPSTREAM_ERROR` | ✅ | | Upstream timeout | 504 `UPSTREAM_ERROR` | ✅ | | Upstream rate-limited (over our provider quota) | 503 `SERVICE_UNAVAILABLE` | ✅ | | Circuit breaker open | 503 `SERVICE_UNAVAILABLE` | ✅ | | Internal server error | 500 `INTERNAL_ERROR` | ✅ | | Not found upstream (nonexistent handle, a transcript with no captions or no speech, etc.) | 404 `RESOURCE_NOT_FOUND` | ✅ | | A list that comes back with no rows | 200, `credits_used: 0` | ✅ | | A video over a transcript endpoint's length limit | 400 `INVALID_REQUEST` | ✅ | | Client-side errors (400/401/402/404 `ENDPOINT_NOT_FOUND`) | 4xx | No charge to refund | | 405 / 409 / 422 | 4xx | No charge to refund | Refunds happen atomically inside the router. Your balance is restored before the error envelope returns. When we retry an upstream internally after a transient failure, you are charged once for the request, never per attempt. There is one more refund you will see on a **successful** call. Metered endpoints deduct an upper-bound ceiling up front and refund the difference as soon as the real cost is known, so a `200` can come back with `credits_used` lower than the deduction. A few list endpoints sell an opt-in row join, such as `include=profile` on the LinkedIn people lanes. The join holds its per-row price for the whole page up front and keeps it only for the rows it actually filled: rows served from cache cost nothing, and rows it could not fill are refunded. The response carries a `hydration` block itemising the rows, the rows filled, the rows served from cache, and the credits held against the credits kept. Composite endpoints refund proportionally when only some legs produce. The batch-by-id endpoints are the exception: `POST /v1/youtube/videos` and `POST /v1/youtube/channels` bill per 50-id chunk however many ids resolve, so there is no per-id refund. A batch that resolves nothing is still refunded in full. ## Labels add no credits The SocialCrawl [labels](/docs/labels.md) that comment, post, review and search lists carry by default never add credits, holds or refunds. A call costs exactly what the same call costs with `judgments=off`, and `data.labels.extra_credits` is `0`. Asking by name for a label that is also a default one, such as `label=sentiment`, is free too, and so is `relevance=filter` with your query as the topic. Only labels that need your own input, or that are not yet measured well enough to be defaults, are metered: `label=mention&brand=`, `label=intent&offer=`, `label=ai_style` on posts, `label=spam`, `toxic` or `low_quality` on comments, `label=reports&reports=` and `label=incentivized` on reviews, and `relevant_to=` on search relevance. Each holds a few credits up front and settles at 1 credit per started 25 rows newly judged on that request; rows already judged for anyone, a page where nothing could be judged, and a cached page cost nothing extra. `brief=` on `/v1/search/creators` adds 2 credits. ## Transcripts cost the same at any length Each transcript endpoint charges a flat price per successful call, whatever the video's duration: 10 credits for TikTok, Instagram and Facebook, 3 for `/v1/youtube/video/transcript`. On TikTok, `use_ai_as_fallback=true` transcribes the audio when the video has no caption track, inside the same 10 credits. AI transcription covers videos up to 10 minutes (600 seconds); Facebook Ad Library ad transcripts cover up to 2 minutes. A longer video, a video with no captions or no speech, and a deleted video are all refunded, and [Error handling](/docs/errors.md#resource-not-found) lists the reason each one carries. `/v1/youtube/video/subtitles` (1 credit) lists a video's caption tracks, each with its language and a download URL. `/v1/youtube/video/transcript` returns the caption text itself, with timestamps. ## How do I know what the next page costs? Every list response carries `pagination.next_page_credits`, the price of sending `next_cursor` back, at your rate. The pages you still want times that number is the most the rest of the list will cost, so check it before you fetch the next page. A page priced by what it returns can come in under the quote, never over it, and on the last page the field is `null`. `pagination.typical_page_size` tells you how many rows a page usually holds. See [What the next page costs](/docs/pagination.md#what-the-next-page-costs). ```json "pagination": { "next_cursor": "sc.eyJ2Ijoy…", "has_more": true, "page_size": 10, "typical_page_size": 10, "next_page_credits": 1 } ``` ## How do I audit what each call cost? Every response, success or error, carries `credits_used` in the body and the same figure in the `X-Credits-Used` header, together with a `request_id`. A cache hit also says `"cached": true` and `X-Cache: HIT`. A background run is the exception: its POST (for example `POST /v1/prism/discover`) answers `X-Credits-Used: 0`, because each search bills on its own after the POST has answered. Read a run's spend from `data.run.credits.spent` on its run route, or each call's `credits` on the run's legs route. Every charge is also in `/v1/credits/transactions` with the run's id. `GET /v1/credits/transactions` costs 0 credits and lists your ledger, newest first. Each row has a `type` (`deduction`, `refund`, `purchase` or `bonus`), a signed `amount`, the `balance_after`, the endpoint and the `request_id`. Filter it with `?request_id=` to see one call: a refunded call shows its deduction and the matching refund, and a cache hit shows no row at all. Page through it with `limit` and `cursor`. `GET /v1/credits/usage` costs 0 credits and totals the credits and requests per API key, UTC day and endpoint, for example `?from=2026-10-01&to=2026-10-22&group_by=api_key,day`. `group_by` takes any of `api_key`, `day` and `endpoint`, comma-separated (default `api_key,day`), and `api_key_id` narrows it to one key. `group_by=endpoint` shows where your credits go, one row per endpoint such as `/v1/tiktok/profile`, and `group_by=api_key,endpoint` gives each client key's spend by endpoint for an invoice. A range covers at most 92 days, because request logs are kept for 90. Any of your keys can read the whole account; keys appear by name and prefix, never the key itself. A `prism/discover` run counts as one request, and its credits include every search and judging step it billed. By endpoint, the searches a run made appear under the lanes they called, with 0 requests, because you did not send them yourself. `GET /v1/keys/current` costs 0 credits and shows the key you call with: its credit limit, what it has used and what is left, and what it can spend right now. See [reading a key's limit](/docs/authentication.md#read-key-limit). A call that walks pages for you (`max_items`, `max_credits`, `max_pages` above 1, `seen`, or a row filter such as `country`, `min_views` or `max_age_days`) is billed page by page, and `max_credits` caps the total: the walk never starts a page that would take the call past it ([Get more in one call](/docs/pagination.md#get-more-in-one-call)). Each page is an ordinary call with its own `request_id`, listed in the response under `data.walk.request_ids`, and that page's deduction and any refund sit under its id. The walk's own `request_id` has no ledger row, and its `credits_used` is the sum of its pages less any `seen` discount. A page served from cache costs nothing, an empty page is refunded in full, and a page whose rows the filter then drops is still charged, because the page itself came back with rows. To reconcile a walk, look up each id in `data.walk.request_ids` with `?request_id=` and add the rows. ## What if my client times out? A request keeps running on our side after your client disconnects, so a call that completes is billed even if you never read the response. Retrying it does not charge you twice. Send the retry with the same `Idempotency-Key` and you get the stored response for 0 credits. If the first attempt is still running, a `GET` retry waits up to 20 seconds for it and returns its result; if it is still running after that, the retry answers `409 IDEMPOTENCY_IN_PROGRESS` with a `Retry-After`. Without a key, a retry inside the endpoint's cache window is a free cache hit. Transcripts stay cached for 30 days. ## Idempotent retries do not double-charge If you send an `Idempotency-Key` header on a call that takes one (every `GET`, and the batch, job and cohort `POST` calls), we guarantee a single charge per key. A few `POST` calls ignore the key, so a retry of one of them can run and bill again. A replay keeps the cached payload immutable except for billing metadata: `credits_used` becomes **0** and `idempotent_replay` becomes `true`. The response sets `X-Idempotent-Replay: true` and `Idempotent-Replayed: true`. A known current balance refreshes body `credits_remaining` and the `X-Credits-Remaining` header; no balance row resolves to 0. On a transient lookup failure, body `credits_remaining` is `null` and `X-Credits-Remaining` is omitted. [Idempotency](/docs/idempotency.md) lists which calls take a key, the ones that ignore it, and the errors a key can produce. ## Topping up Buy credit packs in **Dashboard → Billing**. Packs are one-time purchases, not subscriptions. | Plan | Credits | Price | | ---------- | ------- | ----------------- | | Free | 100 | £0 (signup bonus) | | Starter | 2,500 | £15 | | Growth | 20,000 | £49 | | Pro | 150,000 | £299 | | Enterprise | Custom | Contact us | Credits do not expire. Every purchase, deduction, refund, and bonus is recorded on your transaction history. ## Next steps - [Endpoint pricing](/docs/endpoint-pricing.md): The exact credit cost of every endpoint. - [Caching](/docs/caching.md): Freshness windows, and how cache hits keep your bill down. - [Error handling](/docs/errors.md): Refund rules per error code, and safe retry loops. - [Rate limits](/docs/rate-limits.md): 600 requests per minute and 50 concurrent requests per key.