> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pipecorn.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Credit and limit errors

> How the API reports an exhausted credit balance and workspace spending limits

Every endpoint that spends enrichment credits checks your balance before doing
any work. When that check fails, the API answers with a dedicated status code
and a machine-readable `code`, so your integration can tell "top up and retry"
apart from "this request will never succeed as-is".

## `402 Payment Required` — out of credits

The request was valid, but your workspace does not have enough enrichment
credits to pay for it. No credits are spent, and nothing is enqueued or
imported.

```json theme={null}
{
  "error": "Not enough enrichment credits left",
  "code": "insufficient_credits",
  "top_up_url": "https://app.pipecorn.com/settings/subscriptions/credits"
}
```

| Field        | Description                                                                                                                                                              |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `error`      | Human-readable message. Endpoints priced per result report the shortfall instead, e.g. `"Not enough enrichment credits. You need 30 credits but only have 5 available."` |
| `code`       | Always `insufficient_credits`.                                                                                                                                           |
| `top_up_url` | Absolute URL of your credits page. Send users there to buy credits, then replay the request.                                                                             |

`402` is retryable: top up (or wait for your plan to renew) and send the same
request again.

You can also receive `402` after the pre-flight check passes, if a concurrent
request drains the balance before this one is charged. Treat it the same way.

## `403 Forbidden` — workspace weekly limit reached

Your workspace has a weekly enrichment credit limit and this request would
exceed it. The balance itself is irrelevant here, so no `top_up_url` is
returned — buying credits does not lift the limit.

```json theme={null}
{
  "error": "You have reached your weekly enrichment credit limit for this workspace",
  "code": "workspace_limit_exceeded"
}
```

To unblock, a workspace admin has to raise the member's weekly allowance, or
you wait for the limit to reset.

<Note>
  `403` is also returned when an API key does not have access to an endpoint.
  Branch on `code`, not on the status alone: `workspace_limit_exceeded` is a
  spending limit, anything else is a permission problem.
</Note>

When both conditions apply — the balance is too low *and* the weekly limit is
reached — the API reports the balance first, with `402`.

## Endpoints that return these codes

* [`POST /contacts/single_enrich` (async)](/api-reference/endpoints/enrichments/single) and [`POST /contacts/bulk_enrich`](/api-reference/endpoints/enrichments/batch)
* [`POST /contacts/single_enrich` (synchronous)](/api-reference/endpoints/contacts/sync_single_enrich)
* [`POST /accounts/company_hiring`](/api-reference/endpoints/accounts/company-hiring)
* [`POST /accounts/company_stack`](/api-reference/endpoints/accounts/company-stack)
* [`POST /intents/accounts/hiring`](/api-reference/endpoints/signals/hiring)
* [`POST /intents/accounts/stack`](/api-reference/endpoints/signals/tech_stack)
* `POST /whatsapp_validations`

Preview endpoints are free and never return either code.

Every one of them checks credits up-front, so a rejected request never runs a
provider, creates an import, or enqueues an enrichment.

## Migrating from the previous behaviour

These conditions used to be reported as:

* `422 Unprocessable Entity` — waterfall enrichment (async, bulk, and
  synchronous), WhatsApp validation, `POST /accounts/company_hiring`, and
  `POST /accounts/company_stack`
* `401 Unauthorized` — `POST /intents/accounts/hiring` and
  `POST /intents/accounts/stack`

Both now answer `402` (or `403` for a workspace weekly limit). If your
integration detects an empty balance by matching on `422`/`401`, or by
string-matching the message, switch to the status code and `code` field. `422`
still covers validation errors and `401` still covers authentication, so the
old checks will silently stop firing.
