Skip to content

Error codes

All errors share a consistent JSON envelope:

{
"error": {
"code": "INVALID_API_KEY",
"message": "API key is invalid or no longer recognized.",
"param": null,
"request_id": "req_01J..."
}
}

request_id is also echoed in the response headers; please quote it in support tickets.

CodeHTTPMeaning
MISSING_AUTH401No Authorization header sent.
INVALID_API_KEY401Key not found.
REVOKED_API_KEY401Key was revoked.
WRONG_AUTH_TYPE401Sent an API key to a dashboard endpoint, or a Clerk JWT to a product endpoint.
INVALID_CLERK_TOKEN401JWT failed signature, expiry, or issuer checks.
ACCOUNT_NOT_FOUND404Clerk user has no Nordva Launch account. Call POST /v1/auth/provision.
CodeHTTPMeaning
VALIDATION_ERROR400Body or query fails schema. param names the offending field.
INVALID_PLAN400Plan name not recognised (must be indie or builder).
RATE_LIMITED429Plan rate limit exceeded. Retry-After header included.
PLAN_LIMIT_REACHED403Monthly quota exhausted (for notifications: the project’s notifications for this calendar month, UTC). Upgrade or wait for the cycle to reset.
PLAN_UPGRADE_REQUIRED403Feature gated to a higher plan.
NOT_FOUND404Resource missing or owned by another project.
CANNOT_EDIT_PUBLISHED409Tried to edit a published changelog entry.
HOSTNAME_ALREADY_REGISTERED409Custom hostname already registered to another project.
IDEMPOTENCY_CONFLICT409Same Idempotency-Key used with a different request body.
CodeHTTPMeaning
BILLING_NOT_CONFIGURED503Server-side Paddle environment is not configured.
NO_BILLING_ACCOUNT404Account has no Stripe customer yet: complete a checkout first.
BILLING_PORTAL_UNAVAILABLE502Paddle portal-session API call failed. Retry shortly.
CodeHTTPMeaning
CUSTOM_DOMAIN_NOT_CONFIGURED503Server-side Cloudflare for SaaS env not configured.
CUSTOM_DOMAIN_LIMIT_REACHED403Reached the per-plan custom hostname limit.
CodeHTTPMeaning
KEY_INSUFFICIENT_PERMISSIONS403A publishable key (nv_pub_*) was used on a secret-only endpoint. Publishable keys are browser-safe and may only write to the public endpoints listed in Authentication; list, read, delete, and admin operations require a secret key (nv_live_* / nv_test_*).
API_KEY_LIMIT_REACHED422Project already has the per-plan maximum of active keys of the requested type. Secret and publishable keys are counted independently. Revoke an unused key of the same type, or upgrade the plan.
CodeStatusMeaning
INVALID_SLUG422Slug is not 1–40 lowercase letters, numbers and hyphens.
SLUG_TAKEN409The slug is in use, reserved, or was released by another project in the last 30 days.
INVALID_WEBHOOK_URL422A webhook URL must be a public https:// URL: no IP address, internal hostname, credentials or custom port. message says which rule it broke.
WEBHOOK_LIMIT_REACHED403The project already has as many webhook endpoints as the plan includes (Indie 2, Builder 5).
PROJECT_LIMIT_REACHED403Dashboard only. The account already has as many projects as its plan includes (Free 2, Indie 4, Builder 10).
LAST_PROJECT409Dashboard only. An account keeps at least one project, so its only project cannot be deleted.
PROJECT_NOT_FOUND404Dashboard only. The project named in X-Nordva-Project, or chosen when approving a CLI sign-in, is not one of this account’s.
AFFILIATE_EXISTS409Dashboard only. The account has already applied to the affiliate program.
AFFILIATE_NOT_FOUND404Dashboard only. The account has not joined the affiliate program.
AFFILIATE_INVITE_INVALID404Dashboard only. The affiliate invite link is unknown or was already used.
SLUG_CHANGE_LIMIT_REACHED429The slug was already changed twice in the last 30 days. A project’s first rename, away from the generated slug, is not counted. remediation gives the date it can change again. Old links keep working in the meantime.
CodeStatusMeaning
STRIPE_NOT_CONNECTED409No payment account (Stripe or Lemon Squeezy) is connected to this project. Connect one in the dashboard. The name is older than Lemon Squeezy support.
STRIPE_ALREADY_CONNECTED409Disconnect the current key before connecting another.
STRIPE_KEY_NOT_RESTRICTED422The key is not a restricted key (rk_live_ / rk_test_). If a secret key was pasted, roll it in Stripe.
STRIPE_KEY_INVALID422Stripe did not recognise the key.
STRIPE_KEY_MISSING_PERMISSION422A required read permission is missing. remediation carries Stripe’s message naming it.
STRIPE_CONNECTION_LIMIT_REACHED403Free and Indie include one Stripe connection per account; Builder one per project.
LEMONSQUEEZY_NOT_CONNECTED409No Lemon Squeezy store is connected to this project.
LEMONSQUEEZY_ALREADY_CONNECTED409This project already has a Lemon Squeezy store connected. Disconnect it first.
LEMONSQUEEZY_KEY_INVALID422Lemon Squeezy did not accept the API key: expired, deleted or copied incompletely.
LEMONSQUEEZY_KEY_MISSING_ACCESS422Lemon Squeezy refused one of the reads Launch needs. The message says which.
LEMONSQUEEZY_STORE_NOT_FOUND422The store is not one the key can see. A test mode key only sees test data.
LEMONSQUEEZY_CONNECTION_LIMIT_REACHED403Free and Indie include one Lemon Squeezy store per account; Builder one per project.
STRIPE_CONNECT_NOT_CONFIGURED503Server-side encryption key for Stripe connections is not configured.
CONTACT_NOT_FOUND404No contact with that id in this project.
EMAIL_TEMPLATE_INVALID422Unknown placeholder, missing required placeholder, or empty/too long subject or body. param is subject or body.
CodeHTTPMeaning
USER_HASH_INVALID403A browser call to a notification bell endpoint sent no user_id or user_hash, a hash that does not match the user id, or the project has no signing secret yet. See Identity verification.
SIGNING_SECRET_ALREADY_SHOWN409The project’s notifications signing secret already exists and was shown once when it was made. Rotate it to get a new one; the old one keeps working for 24 hours.
CodeHTTPMeaning
ANALYTICS_UNAVAILABLE503The analytics store could not be read right now. Collection keeps working; try again in a minute.
ANALYTICS_RAW_EVENTS_ONLY400The read follows single visitors or filters by a dimension (visitor lists, one visitor, funnels, hourly buckets, filters), which needs raw events, kept 90 days. Ask for period_days of 90 or fewer. Totals, time series, breakdowns, goals and signups reach back over your plan’s whole history. With param: "exclude_country": a breakdown past 90 days cannot leave countries out; ask for 90 days or fewer, or send exclude_country= to count every country.
CodeHTTPMeaning
INTERNAL_ERROR500Unexpected server error. Include the request_id in your report.
TURNSTILE_FAILED400Cloudflare Turnstile token verification failed.

If you hit a code not listed here, write to [email protected] with the request_id from the response. Codes are never renamed; new ones are added to this page.