Recoup

Get started with Recoup.

Getting started

Credits

How Recoup credits work — what's billed, how to check your balance, and how to upgrade.

On this page

Some Recoup endpoints are billed in credits — primarily endpoints that hit external data providers, run AI inference, or generate content. Check the specific endpoint contract for other charges and subscription gates.


What's billed

FamilyBilled?Notes
Research (/api/research/*)YesEach successful call deducts credits. Costs vary by endpoint and parameters (e.g. enrich charges by processor tier; extract charges by URL count).
Content generation (/api/content/image, video, upscale, transcribe and analyze)YesModel-specific generation and inference charges apply. Hosted pipelines charge their component operations; estimates are advisory.
AI Chat — streaming (POST /api/chat)YesVariable cost based on model token usage, with a per-request minimum.
Music analysis (POST /api/songs/analyze)Yes$0.05 per model request plus $0.001166 per second of inference time; full_report is one batched request for all 13 sections.
Music analysis batch (POST /api/songs/analyze/batch)Yes$0.05 once per batch plus $0.001166 per second of the batch's inference time, however many prompts it carries.
Song moments (POST /api/songs/moments)Yes$0.01 per song measured, plus the music analysis rate for each moment described.
Social scrape (/api/socials/{id}/scrape, /api/artist/socials/scrape)Yes$0.05, plus $0.01 per post requested via posts — per social profile scraped.
Other operationsConsult the endpoint contractArtist CRUD, sandboxes, sessions, scheduled tasks, account/org management, agent signup, Spotify proxies, etc. Subscription gating may still apply.

Upstream generation or inference may incur cost even if a later composition or delivery step fails. Do not infer zero spend from the final pipeline status; inspect usage events. Credit gates reject before provider work when the balance is insufficient.


What a credit is worth

Balances and prices are US dollars. The ledger stores amounts as integer micro-dollars, the same 6-decimal unit as USDC: 1,000,000 = $1.00, so it can carry sub-cent charges (a $0.002/s provider rate prices exactly). Every credit field the API returns is that integer; divide by 1,000,000 to display it as currency. Example: GET /api/accounts/{id}/credits.


Check your balance

bash
curl -sS https://api.recoupable.dev/api/accounts/$ACCOUNT_ID/credits \
  -H "x-api-key: $RECOUP_API_KEY"

Response shape:

json
{
  "account_id": "11111111-1111-4111-8111-111111111111",
  "remaining_credits": 292450000,
  "total_credits": 300000000,
  "used_credits": 7550000,
  "is_pro": true,
  "plan": "pro",
  "task_limit": null,
  "min_cadence_minutes": 60,
  "timestamp": "2026-10-01T12:00:00Z"
}

plan, task_limit, and min_cadence_minutes describe the plan the balance belongs to. total_credits is your plan-derived monthly allotment. remaining_credits can exceed total_credits after a top-up or an admin grant, and used_credits clamps to 0 in that case. Full schema at Get Account Credits.

Plan response examples

is_pro on credits and isPro on subscriptions mean effective Pro, so both are false for paid Starter. Use plan to distinguish Starter from Free. The credits response reports the effective allowance; the subscription response separately identifies whether it comes from the account or an organization.

SituationCredits plan / is_proSubscription sourceTask limit / minimum cadence
Freefree / falsenull1 / weekly
Paid Starterstarter / falseaccount3 / daily
Direct Propro / trueaccountnull (unlimited) / hourly
Starter account with organization Propro / trueorganizationnull (unlimited) / hourly
Inactive subscription without another paid entitlementfree / falsenull1 / weekly

For example, a Pro balance of 325,000,000 against an allowance of 300,000,000 returns used_credits: 0. The API preserves a signed balance: a negative balance can make this display exceed the allowance. This is not a ledger of charges. A null timestamp means the timestamp is unavailable, not proof of no prior activity. An inactive subscription resolves to status: "none" and null subscription/billing fields; this endpoint does not return the canceled subscription's history. Billing details may also be unavailable on an active response. Named reference examples illustrate these states without quoting an available offer or a live payment.

To see what consumed the balance, list the charges line by line with GET /api/accounts/{id}/usage: one item per deduction, newest first, each with the amount in micro-dollars and as a dollar string, plus the total for the period. API charges name the endpoint that billed them in model_id (for example POST /api/artist/socials/scrape), so a list of charges reads as a list of calls.


Subscription

For Platform, Advisory, Build + Partner, and Enterprise options, see Recoup pricing. API and MCP usage is billed separately through credits.

Your account's current credit allowance and scheduled-task limits are returned by Get Account Credits. Use total_credits, task_limit, and min_cadence_minutes from that response rather than inferring limits from a public plan name.

The API may return account identifiers such as free, starter, or pro. These are documented API values; they are not the names of consulting engagements. The request and response schemas define the values accepted by each endpoint.

Task limits

POST /api/tasks and PATCH /api/tasks check the plan before writing. Creating a task past task_limit, re-enabling a disabled task past it, or saving a cron whose consecutive runs are closer together than min_cadence_minutes returns HTTP 402 with error: "plan_limit":

json
{
  "status": "error",
  "error": "plan_limit",
  "limit": "task_count",
  "message": "Free includes 1 task. Starter includes 3, Pro is unlimited.",
  "plan": "free",
  "task_limit": 1,
  "min_cadence_minutes": 10080,
  "current_task_count": 1,
  "billingUrl": "https://app.recoupable.dev/plan"
}

limit is task_count or min_cadence; current_task_count excludes the task being created or updated. Edits that only touch title, prompt, or model never hit the gate.

Monthly refill

The refill is a floor, not an assignment. It raises remaining_credits up to your plan's monthly total and never lowers it. A balance already above the plan total, whether from a top-up or an admin grant, is left exactly as it is, so credits you bought or were granted are never taken away by the calendar.

The refill is lazy rather than scheduled: it applies on the next read of GET /api/accounts/{id}/credits once your credits row is more than a month old. The balance you read is always the refilled one.

Manage your subscription

Sign in to your account billing page to review your subscription, price, and current terms. For programmatic checkout, use the accepted request values in Create Subscription Session and open its returned checkout URL. Review the price and billing terms before completing checkout.

Advisory and custom-build engagements begin with a conversation about scope. Their website plan selection does not create an API subscription or complete a payment.

Check your tier

bash
curl -sS https://api.recoupable.dev/api/accounts/$ACCOUNT_ID/subscription \
  -H "x-api-key: $RECOUP_API_KEY"

Get $ACCOUNT_ID from GET /api/accounts/id if you don't already have it. Response includes isPro (boolean), status, plan, and source (whether the subscription comes from the account itself or an organization the account belongs to). Full schema at Get Subscription.

One-time top-ups

You can purchase credits any time via POST /api/credits/sessions. The endpoint adapts to what's on the account:

  • Card on file → silent auto-charge. Recoup charges your saved Stripe card off-session and returns paymentIntentId, creditsPurchased, and totalCents. Credits land within seconds.
  • No card, or Stripe declines the saved card → Stripe Checkout fallback. The response contains a Checkout url you open in the browser. When Stripe specifically declined a saved card, the response also includes a declineReason (e.g. insufficient_funds, expired_card) so you can explain why before sending the customer to update billing.
bash
curl -sS -X POST https://api.recoupable.dev/api/credits/sessions \
  -H "x-api-key: $RECOUP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"credits": 1000000, "successUrl": "https://chat.recoupable.dev/credits/success"}'

Full request/response schema at Create Credits Top-Up Session.

Check which card will be charged

Before triggering a silent off-session charge, inspect the default payment method on file:

bash
curl -sS https://api.recoupable.dev/api/accounts/$ACCOUNT_ID/payment-method \
  -H "x-api-key: $RECOUP_API_KEY"

Response shape:

json
{
  "account_id": "11111111-1111-4111-8111-111111111111",
  "card": {
    "brand": "visa",
    "last4": "4242",
    "exp_month": 12,
    "exp_year": 2026,
    "funding": "credit"
  }
}

card is null when this lookup finds no supported default card, including when no tagged Stripe customer exists. It does not establish whether a card was saved previously or whether other saved cards remain. Removing one selected card can leave others available; read the current card and auto-top-up settings before deciding how to proceed. Expired cards are still returned (with their original exp_month / exp_year); callers should compare against the current date and warn the customer, since an off-session charge against an expired card will decline. Full schema at Get Default Payment Method.


Running out of credits

Every billed API request runs a credit gate before it executes. If remaining_credits doesn't cover the request's cost, the request stops there and returns HTTP 402. Nothing is charged and no Stripe object is created.

The decision tree:

  1. Enough credits? → Request proceeds, credits deducted on success.
  2. Short? → Request returns HTTP 402 with the balance, the cost, and a link to billing.

A card on the account is never charged on its own. Charging happens only when the account asks to buy credits, through POST /api/credits/sessions, or when the account has turned on auto top-up. Saving a card ahead of time via POST /api/accounts/{id}/payment-method makes a one-time purchase a single call instead of a browser round-trip; it does not authorize a charge by itself. Your plan, card, and every payment are on /api/accounts/{id}/subscription, /api/accounts/{id}/payment-method, and /api/accounts/{id}/payments; pass an organization id as {id} to read the organization's billing.

Auto top-up (opt-in)

Auto top-up is off for every account until it is turned on with PUT /api/accounts/{id}/auto-top-up, which needs three things chosen by the account: enabled, the amountCents to buy each time (5.00 to 1,000.00 USD), and the thresholdCents balance that triggers it. Both are USD cents; the remaining_credits balance above is in credit micro-dollars, so divide it by 10,000 to compare. Turning it on requires a card on file.

Once on, a credit deduction classified as web can trigger a purchase when the balance falls below the threshold. API-sourced deductions, including plugin and API-triggered background work, spend existing credits and do not trigger auto-top-up, even when the account has enabled it. This does not change the account's saved settings. Eligible top-ups charge the card for the amount, grant credits, record a usage event and email a receipt. Guardrails: at most one top-up per account per 10 minutes; a card decline turns auto top-up off, records the decline message as lastError (returned by GET /api/accounts/{id}/auto-top-up), and emails the account instead of retrying; a successful selected-card removal turns it off before detachment, even when other cards remain. Auto top-up never creates a checkout session and never touches an invoiced (enterprise) plan. Saving a card does not turn auto top-up on by itself.

Remove a saved card

DELETE /api/accounts/{id}/payment-method turns off automatic credit purchases, then removes the selected saved card. It removes one card, preserving other cards, balances, and configured amounts and thresholds. It does not cancel subscriptions or invoices. Other saved cards can still appear in a later card read and fund a purchase you explicitly request; removal does not silently enable automatic purchases again.

Success returns 204 with no body. If no customer or selected card exists, 404 leaves settings and cards unchanged. A 500 can mean the settings save failed before card removal, or that settings were saved but detachment failed; in the latter case automatic purchases stay off. Read the current card and auto-top-up settings before retrying an error or uncertain response. Repeating DELETE after a completed removal may select and remove another card.

This operation does not cancel a charge already in progress or prevent someone from explicitly changing the settings concurrently.


402 Payment Required

When the gate comes up short, billed endpoints return HTTP 402 with a unified body:

json
{
  "error": "insufficient_credits",
  "remaining_credits": 120000,
  "required_credits": 1000000,
  "billingUrl": "https://app.recoupable.dev"
}

FieldWhen it appearsMeaning
errorAlwaysLiterally "insufficient_credits"
remaining_creditsAlwaysAccount balance at the moment of the failed request
required_creditsAlwaysWhat this endpoint needed
billingUrlAlwaysStatic link to the Recoup app, where a human can save a card and buy credits

billingUrl is a constant, not a freshly minted Stripe Checkout Session. Retrying a credit-gated endpoint returns the same URL every time and creates nothing, so an unattended client that keeps hitting the gate is safe to leave running.

How to react:

  • Browser-driven UI (e.g., the Recoup chat app): send the customer to billingUrl, or call POST /api/credits/sessions inline and open the url it returns.
  • Direct REST client outside the plugin: report remaining_credits and required_credits and handle billingUrl according to that client's billing interface. Do not treat a 402 as retryable.
  • Recoup plugin / MCP workflow: preserve the task and explain the missing entitlement. Do not surface billing or checkout links, advertise plans, start subscriptions or credit purchases, or use another connector to bypass the limit. Use only existing entitlements; resume only after access is independently available and the user asks to continue.

Cost per endpoint

Current as of this revision of the page. The authoritative source is the per-endpoint reference docs and the required_credits field on any 402 response.

EndpointCost
POST /api/chat (streaming)Variable, priced from the model's token usage; see required_credits on a 402
Recoup artist and track research$0.05 per successful research call (50,000 credits); track-name resolution can add separately charged provider lookups
POST /api/research/people$0.05 per call
POST /api/research/web$0.01 per call
POST /api/research/extract$0.05 × number of URLs
POST /api/research/enrich$0.05 / $0.10 / $0.25 (base / core / ultra processor)
POST /api/research/deep$0.25 per call
POST /api/image/generatePer-call price; see endpoint reference
POST /api/songs/analyze$0.05 + $0.001166 × elapsed_seconds per model request; full_report is one request
POST /api/songs/analyze/batch$0.05 + $0.001166 × elapsed_seconds once per batch, elapsed_seconds being the whole batch
POST /api/songs/moments$0.01 per song measured, plus $0.05 + $0.001166 × elapsed_seconds once for the moments described

Billing recovery and units

The REST insufficient_credits body retains billingUrl, a static app link, not a Stripe Checkout session. Plugin workflows must not surface that transactional recovery link or initiate a charge. The release-pack MCP adapter omits it from errors. The historical measurement gate returns payment_method_required and a neutral message, without checkoutUrl or session creation; subscription Checkout returns url. Inspect the endpoint-specific error type.

Top-ups require successUrl on every request and a positive whole-cent multiple of 10,000 micro-dollar credits. For example, 2,500,000 credits buys $2.50 before fees; totalCents is 289 for that example. It is not a credit count. isPro means effective Pro only, and is false for paid Starter; use plan for paid-plan decisions.

Scheduled task creation and updates can return a plan-limit 402; task reads do not run that gate. Free/Starter/Pro are technical entitlement values. Platform/Advisory/Build/Enterprise marketing offers describe commercial services; they are not interchangeable names.