REFERENCE
Errors
Every error the NoChurn API returns (41 codes): HTTP status, message, how to fix it and when it happens.
Error format
Every error has the same body, whatever the endpoint: a stable code, a readable message, a fix that says
what to do, and a docs_url that points to the section of this page. Branch on code and the HTTP status, never on the
message, which can change.
{
"error": {
"code": "customer_not_found",
"message": "No customer matches this identifier.",
"fix": "A customer can be referenced three ways: `customer` (NoChurn id cst_…), `stripe_customer` (Stripe id cus_…, plus `stripe_account` if several Stripe accounts are connected) or `external_id` (the id in your app). Check the value and the mode of your key (test or live).",
"docs_url": "https://nochurn.sh/docs/errors#customer_not_found"
}
} Some messages name the parameter or the object at fault, so they can be more precise than the generic message listed below.
All codes
| Code | HTTP | Message |
|---|---|---|
unauthorized | 401 | Missing, unknown or revoked API key. |
forbidden | 403 | This API key is not allowed to perform this action. |
two_factor_required | 403 | This account requires two-factor authentication. |
publishable_key_required | 403 | This endpoint takes a publishable key (pk_…), not a secret key. |
test_mode_only | 403 | This endpoint only works in test mode. |
invalid_request | 400 | The request is invalid. |
not_found | 404 | The requested resource does not exist. |
conflict | 409 | The request conflicts with the current state of the resource. |
payload_too_large | 413 | The request body is too large. |
rate_limited | 429 | Too many requests. |
internal_error | 500 | Something went wrong on our side. |
customer_not_found | 404 | No customer matches this identifier. |
ambiguous_customer | 409 | Several customers match this identifier. |
subscription_not_found | 404 | No live subscription of this customer matches this identifier. |
subscription_required | 422 | This customer has several live subscriptions: say which one to cancel. |
nothing_to_resume | 409 | No paused subscription to resume. |
attribute_limit_reached | 429 | This account already has 100 custom attributes. |
attribute_type_mismatch | 422 | An attribute was sent with the wrong type. |
insufficient_data | 422 | Not enough activity yet for an AI analysis of this customer. |
stripe_not_configured | 503 | Stripe is not configured on this server. |
stripe_error | 502 | Stripe returned an error. |
provider_error | 502 | The billing provider returned an error. |
provider_not_available | 422 | This billing provider is not available yet. |
capability_missing | 409 | The billing provider does not allow this action. |
import_access_denied | 502 | The billing tool refused NoChurn's access during the import. |
import_failed | 502 | The import stopped on an error. |
import_interrupted | 503 | The billing tool did not answer during the import. |
dispute_already_submitted | 409 | This dispute's reply was already submitted. |
dispute_not_supported_by_provider | 409 | This provider handles its disputes itself. |
email_domain_provisioning_failed | 502 | NoChurn could not prepare the DNS records of this domain with its email provider. |
plan_payment_required | 402 | Your NoChurn subscription is unpaid: emails, payment retries and AI are suspended for this account. |
plan_billing_not_configured | 503 | NoChurn billing is not configured on this server. |
custom_plan_required | 409 | Your tracked MRR is above the last self-serve tier: NoChurn prices this account with you. |
insufficient_scope | 403 | This OAuth token does not have the scope this endpoint needs. |
live_read_not_granted | 403 | This AI app may not read live data. |
live_approval_required | 403 | AI apps connected through OAuth never change live mode directly. |
evidence_file_too_large | 413 | Evidence files are limited to 5 MB each. |
evidence_file_unsupported | 415 | Evidence files must be PDF, JPEG or PNG. |
evidence_files_limit | 422 | This dispute has as many evidence files as the bank can receive. |
logo_too_large | 413 | Logos are limited to 1 MB. |
logo_unsupported | 415 | Logos must be PNG, JPEG or WebP images. |
Authentication and rights
unauthorized 401
- Message
- Missing, unknown or revoked API key.
- When
- The Authorization header is missing, or the API key or OAuth token is unknown, expired or revoked; for browser endpoints, the customer token is missing or invalid; in the dashboard, the session has expired or a code or password is wrong.
- Fix
- Send a valid key in the Authorization header ("Authorization: Bearer nc_live_…"). Create one in the dashboard, under Developers › API keys.
forbidden 403
- Message
- This API key is not allowed to perform this action.
- When
- The key or user may not do this: a restricted key without the level the resource needs, a publishable key on a secret-key endpoint, an origin not allowed for the key, a role below the one required, a live action on a server where live mode is off, or an endpoint reserved to the dashboard.
- Fix
- Use a key with the required mode and scope.
two_factor_required 403
- Message
- This account requires two-factor authentication.
- When
- The account requires two-factor authentication and the signed-in member has not turned it on, or an AI app is authorized for such an account by a member without it.
- Fix
- Turn on two-factor authentication in Settings › Security, then retry.
publishable_key_required 403
- Message
- This endpoint takes a publishable key (pk_…), not a secret key.
- When
- A browser endpoint (widget, in-app, cancel sessions) is called with a secret key (nc_…) instead of a publishable key (pk_…).
- Fix
- Use your publishable key from Developers. If a secret key (nc_…) was ever in a web page, roll it now.
test_mode_only 403
- Message
- This endpoint only works in test mode.
- When
- A sandbox scenario (POST /v1/sandbox/…) or POST /v1/integration/verify called in live mode.
- Fix
- Use a test key (nc_test_…) or the dashboard in test mode. Going live is done by a human in the dashboard.
Requests
invalid_request 400
- Message
- The request is invalid.
- When
- A parameter is missing, unknown or has the wrong format, the JSON body cannot be parsed, a value fails validation (then with HTTP 422), or the NoChurn-Mode header is neither test nor live. The message names the parameter.
- Fix
- Check the request parameters against the API reference.
not_found 404
- Message
- The requested resource does not exist.
- When
- The id in the path does not exist in the account and mode of the key, or the URL matches no endpoint. Ids of another account are never revealed: they are not found too.
- Fix
- Check the ID and that it belongs to the account of your API key.
conflict 409
- Message
- The request conflicts with the current state of the resource.
- When
- The resource is not in a state that allows the action: an import already running, a revoked or disconnected connection, an invitation already accepted, two-factor already on, a help desk or Slack not connected, and similar cases. The message says which.
- Fix
- Fetch the resource to see its current state before retrying.
payload_too_large 413
- Message
- The request body is too large.
- When
- A widget events batch (POST /v1/widget/events) whose body is larger than the limit.
- Fix
- Send fewer events per call.
rate_limited 429
- Message
- Too many requests.
- When
- Too many requests in a short time (sign-in, two-factor, invitations, widget events), or a daily quota reached (AI analyses, AI email samples, test emails), or a refresh asked again within the hour. The response gives retry_after in seconds.
- Fix
- Wait retry_after seconds, then retry.
internal_error 500
- Message
- Something went wrong on our side.
- When
- An unexpected error on NoChurn's side, or a server-side service that could not be reached (for example an email that could not be sent or an AI analysis that was rejected). Retrying is safe.
- Fix
- Retry later. If it persists, contact support with the request ID.
Customers and subscriptions
customer_not_found 404
- Message
- No customer matches this identifier.
- When
- No customer of the key's mode (test or live) matches the
customer,stripe_customerorexternal_idyou sent, on any endpoint that takes a customer reference, the widget and the in-app calls included. - Fix
- A customer can be referenced three ways:
customer(NoChurn id cst_…),stripe_customer(Stripe id cus_…, plusstripe_accountif several Stripe accounts are connected) orexternal_id(the id in your app). Check the value and the mode of your key (test or live).
ambiguous_customer 409
- Message
- Several customers match this identifier.
- When
- A
customerreference matches more than one customer, for example a Stripe id (cus_…) shared by several connected Stripe accounts, or a value that is one customer's external_id and another's Stripe id. - Fix
- Use an explicit parameter instead of
customer:stripe_customer(withstripe_accountwhen several Stripe accounts are connected) orexternal_id.
subscription_not_found 404
- Message
- No live subscription of this customer matches this identifier.
- When
- The
subscriptionsent to a cancel session or to POST /v1/inapp/resume (nsub_…, sub_… or the billing's own id) is not one of the customer's live subscriptions in this mode. - Fix
- Pass one of the customer's live subscriptions: NoChurn id (nsub_…), Stripe id (sub_…) or its id in your billing (the external_id you sent by API, or the billing tool's own id). It must belong to the customer of the token and to the mode of your key (test or live).
subscription_required 422
- Message
- This customer has several live subscriptions: say which one to cancel.
- When
- Cancelling, or resuming with POST /v1/inapp/resume, for a customer with several live (or paused) subscriptions without saying which one.
- Fix
- Send { subscription: "nsub_…" } with one of the session's
subscriptions, or sign the widget token with asubscriptionclaim.
nothing_to_resume 409
- Message
- No paused subscription to resume.
- When
- POST /v1/inapp/resume when the customer has no subscription paused right now.
- Fix
- Fetch GET /v1/inapp/state: the subscription is already active (or was never paused).
attribute_limit_reached 429
- Message
- This account already has 100 custom attributes.
- When
- Sending custom attributes (POST /v1/customers/{id}/attributes, or attributes on a customer create or update) or declaring one (POST /v1/attribute_definitions) would take the account past 100 attribute keys.
- Fix
- Reuse an existing attribute, or delete one you no longer send.
attribute_type_mismatch 422
- Message
- An attribute was sent with the wrong type.
- When
- A custom attribute is sent with a different type than the one it already has (for example a string for an attribute first sent as a number), or declared again with another type.
- Fix
- Send the same type as before, or ask support to reset the attribute.
insufficient_data 422
- Message
- Not enough activity yet for an AI analysis of this customer.
- When
- Asking for the AI analysis of a customer (POST /v1/customers/{id}/insight) who has no subscription, payment, invoice, custom attribute, support conversation or cancel flow session yet.
- Fix
- Nothing to do: the analysis becomes available once the customer has a subscription, a payment, an invoice, custom attributes, a support conversation or a cancel flow session.
Billing and providers
stripe_not_configured 503
- Message
- Stripe is not configured on this server.
- When
- A Stripe endpoint (connect, import, Stripe webhooks) on a server where the Stripe keys or the Connect client id are not set. Self-hosted and development servers only.
- Fix
- Set STRIPE_TEST_SECRET_KEY and STRIPE_CONNECT_CLIENT_ID (see .env.example). Outside production, only Stripe test mode is available.
stripe_error 502
- Message
- Stripe returned an error.
- When
- Stripe refused a call NoChurn made: connecting a Stripe account with Stripe Connect, or a NoChurn plan checkout or billing portal request.
- Fix
- Retry in a moment. If it persists, reconnect your Stripe account from Integrations.
provider_error 502
- Message
- The billing provider returned an error.
- When
- The billing or payment provider refused or failed a call NoChurn made for you: accepting a dispute, uploading evidence, submitting a reply, or reading a provider webhook in time.
- Fix
- Retry in a moment. If it persists, check the connection in Integrations (keys, permissions).
provider_not_available 422
- Message
- This billing provider is not available yet.
- When
- Connecting a billing provider that NoChurn does not support yet (POST /v1/billing_connections), or signing in with Google on a server where it is not set up.
- Fix
- Stripe and billing by API are available today; the other providers arrive milestone by milestone.
capability_missing 409
- Message
- The billing provider does not allow this action.
- When
- The connected billing tool cannot do what was asked through NoChurn: an import on a provider without one, resuming a paused subscription, or an offer the provider does not support (for example some offers on Chargebee, Maxio or Zuora).
- Fix
- See the capabilities of the connection (GET /v1/billing_connections/:id): the action stays with the provider.
import_access_denied 502
- Message
- The billing tool refused NoChurn's access during the import.
- When
- Not returned by a request: it is the error of an import (the backfill of a billing connection or of Stripe) when the billing tool refused NoChurn's access, for example a revoked key or a missing permission.
- Fix
- Reconnect %{provider} from Integrations (the access was revoked, or a key or permission is missing), then retry the import.
import_failed 502
- Message
- The import stopped on an error.
- When
- Not returned by a request: it is the error of an import (the backfill of a billing connection or of Stripe) that stopped on an error that is neither an access problem nor a timeout.
- Fix
- Retry the import from Integrations: it is safe to re-run. If it stops again, write to support@nochurn.sh with this message.
import_interrupted 503
- Message
- The billing tool did not answer during the import.
- When
- Not returned by a request: it is the error of an import (the backfill of a billing connection or of Stripe) when the billing tool did not answer in time or rate-limited NoChurn.
- Fix
- %{provider} did not answer or limited the requests. Retry the import from Integrations in a few minutes: it is safe to re-run, nothing is imported twice.
dispute_already_submitted 409
- Message
- This dispute's reply was already submitted.
- When
- Changing the evidence of a dispute, attaching or removing a file, submitting the reply or accepting the dispute after its reply was sent, or once it is closed.
- Fix
- A reply is final: follow the outcome on the dispute page.
dispute_not_supported_by_provider 409
- Message
- This provider handles its disputes itself.
- When
- Submitting, accepting or changing the evidence of a dispute whose payment provider handles disputes itself (a read-only dispute in NoChurn).
- Fix
- Reply from the provider's dashboard: NoChurn shows the dispute and follows its outcome.
email_domain_provisioning_failed 502
- Message
- NoChurn could not prepare the DNS records of this domain with its email provider.
- When
- Not returned by a request: it is the error stored on a sending domain when NoChurn's email provider could not create its DNS records (the domain's error field).
- Fix
- Click Regenerate to try with a new subdomain. Until then, emails keep coming from your NoChurn address.
NoChurn plan
plan_payment_required 402
- Message
- Your NoChurn subscription is unpaid: emails, payment retries and AI are suspended for this account.
- When
- A write that would start outbound activity (emails, payment retries, AI) while the account's NoChurn subscription is unpaid, or while a free account's live MRR is past the free plan's limit. Reads, ingestion and click to cancel are never blocked.
- Fix
- Update your card in Settings › Billing (Manage card and invoices). Everything resumes as soon as the invoice is paid.
plan_billing_not_configured 503
- Message
- NoChurn billing is not configured on this server.
- When
- A NoChurn plan endpoint (plan, checkout, billing portal, invoices) on a server where NoChurn's own Stripe billing or its prices are not set up. Self-hosted and development servers only.
- Fix
- Set STRIPE_TEST_SECRET_KEY and STRIPE_BILLING_WEBHOOK_SECRET, then run bin/rails nochurn:billing:setup_prices (see .env.example). Outside production, only Stripe test mode is available.
custom_plan_required 409
- Message
- Your tracked MRR is above the last self-serve tier: NoChurn prices this account with you.
- When
- Starting a checkout for a NoChurn plan when the account's tracked MRR is above the last self-serve tier, or when the account is already on a custom plan.
- Fix
- Contact support (support@nochurn.sh) for a custom plan.
AI apps (OAuth)
insufficient_scope 403
- Message
- This OAuth token does not have the scope this endpoint needs.
- When
- An AI app's OAuth token (ncat_…) calls an endpoint, or asks for a live request, that needs a scope it was not granted (read, configure or sandbox).
- Fix
- Authorize the AI app again with the missing scope (read, configure or sandbox).
live_read_not_granted 403
- Message
- This AI app may not read live data.
- When
- An AI app's OAuth token sends NoChurn-Mode: live to read live data when the person who connected it did not allow "Live data: read".
- Fix
- Read test mode instead (drop the NoChurn-Mode header), or ask an owner or admin of the NoChurn account (or the person who connected the app) to turn on "Live data: read" for this app in the dashboard, Settings › AI apps.
live_approval_required 403
- Message
- AI apps connected through OAuth never change live mode directly.
- When
- An AI app's OAuth token tries to change live mode (a write with NoChurn-Mode: live, publishing a flow live, creating a live API key). It must ask a human with POST /v1/live_requests instead.
- Fix
- Ask a human to approve it: POST /v1/live_requests { "action": "<operation>", "params": { … }, "reason": "…" } returns an approval_url to give to an owner or admin of the NoChurn account (operations: create_live_api_key, publish_flow_live, set_billing_source, create_webhook_endpoint, create_customer… see the LiveRequestCreate schema in openapi.yaml).
Files
evidence_file_too_large 413
- Message
- Evidence files are limited to 5 MB each.
- When
- Attaching an evidence file of more than 5 MB to a dispute (POST /v1/disputes/{id}/evidence_files).
- Fix
- Compress the PDF or lower the image resolution, or split it into several files, then attach it again.
evidence_file_unsupported 415
- Message
- Evidence files must be PDF, JPEG or PNG.
- When
- Attaching an evidence file to a dispute that is not a PDF, JPEG or PNG, read from the file's bytes rather than its name.
- Fix
- Export the document as a PDF (or take a PNG or JPEG screenshot), then attach it again.
evidence_files_limit 422
- Message
- This dispute has as many evidence files as the bank can receive.
- When
- Attaching an evidence file to a dispute that already has as many files as the payment provider accepts, or files that do not fit the provider's evidence fields.
- Fix
- Remove or exclude a file, or combine several documents into one PDF.
logo_too_large 413
- Message
- Logos are limited to 1 MB.
- When
- Uploading a cancel flow logo of more than 1 MB (POST /v1/flows/{id}/logos).
- Fix
- Export a smaller image (a logo shown at 28 px high needs about 200 px), then upload it again.
logo_unsupported 415
- Message
- Logos must be PNG, JPEG or WebP images.
- When
- Uploading a cancel flow logo that is not a PNG, JPEG or WebP image (read from its bytes; SVG is refused), or that is more than 4000 px on a side.
- Fix
- Export your logo as a PNG (transparent background) or WebP, 4000 px at most per side, then upload it again. SVG is not accepted.