Skip to content

Error reference

Every error code the URLCrop API returns, with its HTTP status, type and when it happens.

Error format

Every error response uses one JSON envelope. Branch on code, never on message. Send the request_id to support when you need help. See pagination, rate limits and idempotency for retries.

{
  "error": {
    "type": "validation_error",
    "code": "slug_taken",
    "message": "The slug \"diwali\" is already in use on crop.sh.",
    "param": "slug",
    "request_id": "req_01JB4N8ZK3Q9WXYZ0123456789",
    "doc_url": "https://urlcrop.com/docs/api/errors#slug_taken",
    "details": [
      { "path": "slug", "code": "slug_taken", "message": "Already in use" }
    ]
  }
}

invalid_request_error

invalid_jsonHTTP 400

Invalid JSON body

Body not parseable

invalid_queryHTTP 400

Invalid query parameter

Query parameter wrong type / unknown value

missing_headerHTTP 400

Required header missing

X-Workspace-Id missing on a session request

invalid_cursorHTTP 400

Invalid pagination cursor

Cursor malformed or from a different sort

invalid_sortHTTP 400

Invalid sort field

Unknown sort field

invalid_expandHTTP 400

Invalid expansion

Unknown expansion

payload_too_largeHTTP 413

Payload too large

Body over limit

unsupported_media_typeHTTP 415

Unsupported media type

Wrong Content-Type

authentication_error

unauthenticatedHTTP 401

Authentication required

The single 401 code. details[0].code gives the reason: missing_credentials, invalid_api_key, api_key_revoked, api_key_expired, session_expired, oauth_grant_revoked, oauth_token_expired, publishable_key_not_allowed (a uc_pub_ key on anything but POST /v1/collect), internal_signature_invalid

permission_error

two_factor_requiredHTTP 403

Two-factor authentication required

TOTP enabled, second factor not completed for this session; or (param: two_factor, details[0].code = two_factor_grace_expired, details[0].grace_ends_at) a session write by an Owner/Admin on Business, Agency or Enterprise without 2FA after the 14-day grace. Reads, API keys and redirects are unaffected

step_up_requiredHTTP 403

Recent re-authentication required

The action needs a fresh authentication; the dashboard opens the re-authentication prompt and retries

email_verification_requiredHTTP 403

Email verification required

Unverified account on any create route (links, QR, pages, domains, API keys, invitations), on POST /v1/invitations/accept or on a billing route; the response carries a resend hint.

signups_pausedHTTP 403

New sign-ups are paused right now. Join the waitlist or check back soon.

New sign-ups are paused (platform_settings.signups_paused) on /sign-up/email and first OAuth sign-in; existing accounts sign in normally.

insufficient_scopeHTTP 403

API key scope missing

Key lacks the scope; param = the required action name (e.g. links.create)

insufficient_roleHTTP 403

Role does not allow this action

Role does not allow the action (a non-member gets 404 resource_not_found)

workspace_mismatchHTTP 403

Workspace does not match the credential

X-Workspace-Id differs from the key's workspace

wrong_environmentHTTP 403

Credential used in the wrong environment

Test-mode credential on a live-only route (/v1/billing/checkout-sessions with real payment) or live credential on /v1/test/*

workspace_suspendedHTTP 403

Workspace suspended

Suspended for abuse; reads allowed, writes blocked

write_blocked_past_dueHTTP 403

Workspace is read-only (payment past due)

Dunning day 7+: workspace read-only, no new links/QR/pages; reads still succeed

content_policy_holdHTTP 403

Page is on a content policy hold

A page held for a content policy violation cannot be republished by its owner; the hold is lifted by staff only

origin_not_allowedHTTP 403

Origin not allowed

Session request from a non-allowlisted Origin

turnstile_failedHTTP 403

Bot challenge failed

Public endpoint without a valid Turnstile token

second_approver_requiredHTTP 403

A different staff member must approve this action

Staff console only: the action needs a second, different staff member to approve it (duplicate-charge correction, staff role grant, kill switch on a paid workspace), and the caller requested it or no other eligible approver exists

view_as_read_onlyHTTP 403

Support view is read-only

A write was attempted during a read-only support view of the workspace; the support session can only read

support_access_approval_requiredHTTP 403

Customer approval needed

Staff console only: "view as" refused because the Enterprise Organization set support_access = 'on_request' and the workspace has no live customer grant (/v1/workspaces/{id}/support-access/grants)

plan_limit_error

feature_not_in_planHTTP 403

Feature not in plan

Feature absent from the plan: API on Free/Starter, bulk below Pro, Convert below Business…; param = plan limit key (api_requests_per_day, bulk_csv, convert, smart_routing, retargeting_pixels, link_controls, custom_slugs, custom_domains, …)

plan_limit_reachedHTTP 403

Plan limit reached

A numeric entitlement is exhausted; param is plan limit key: links_per_month, dynamic_qr_total, pages_total, custom_domains, seats, client_workspaces, webhook_endpoints, events_per_month, or downgrade (resource above the new plan's limit is read-only). details[0] carries limit, used, resets_at and upgrade_to

not_found_error

resource_not_foundHTTP 404

Resource not found

Id does not exist **or belongs to another workspace** (never distinguished); also a session X-Workspace-Id the user is not an active member of

route_not_foundHTTP 404

Route not found

Unknown path

conflict_error

slug_takenHTTP 409

Slug already in use

Slug exists on that domain

domain_already_existsHTTP 409

Domain already registered

Hostname registered (by this or another workspace)

member_already_existsHTTP 409

Already a member

Already a member

invitation_pendingHTTP 409

Invitation already pending

Pending invitation for that email

idempotency_in_progressHTTP 409

Request with this idempotency key in progress

Same Idempotency-Key executing

state_conflictHTTP 409

Invalid for the current state

Invalid for current state (publish a published page, verify an active domain, cancel a canceled subscription, erase while owning workspaces, restore a workspace after its 30-day window, transfer ownership to a member who already owns a workspace, attach a QR code to a link that already has a live one — param: link_id)

resource_in_useHTTP 409

Resource in use

Delete blocked: a domain with active links unless ?force=true; an asset used by a live QR code (no force)

validation_error

validation_failedHTTP 422

Validation failed

Zod failure; see details

destination_invalidHTTP 422

Destination URL not allowed

Not absolute http(s), private IP, credentials in the URL, too long, or points at a URLCrop domain; details[0].code gives the reason (unparseable, scheme_not_allowed, has_credentials, not_public, is_urlcrop, too_long)

destination_blockedHTTP 422

Destination blocked by link safety

Safety: denylist entry, feed hit or a fresh malicious verdict only; unknown risk creates the link as pending instead. A content-policy list hit (adult, gambling, hacking, csam/terror) adds details[0].code: policy_violation with param set to the category

destination_unreachableHTTP 422

Destination unreachable

Health pre-check failed with require_reachable=true

slug_invalidHTTP 422

Slug invalid

Outside [A-Za-z0-9_-], length 1–64, or starts with @

slug_reservedHTTP 422

Slug reserved

Reserved word (api, docs, p, qr, admin, t, @*, …)

domain_not_activeHTTP 422

Domain not active

Link/page assigned to a domain whose status is not active

domain_proxiedHTTP 422

Domain must be DNS-only

Hostname resolves to Cloudflare proxy IPs (orange cloud) instead of the VPS; must be DNS-only

idempotency_key_reusedHTTP 422

Idempotency key reused with a different body

Same key, different body

unsupported_qr_typeHTTP 422

QR type not supported

QR type not in this phase/plan (Phase 2 types google_review, menu, app_store, sms, email)

qr_unreadableHTTP 422

QR code would not scan

The QR design failed the server decode test (contrast, logo coverage or shapes); returned by render requests; the code is saved, but no render is produced until the design is fixed

invalid_routing_ruleHTTP 422

Invalid routing rule

Contradictory conditions or A/B weights ≠ 100

invalid_currencyHTTP 422

Invalid currency

Not INR/USD or not matching billing country

csv_invalidHTTP 422

CSV import invalid

Import errors; details lists rows

attribution_key_missingHTTP 422

Attribution key missing

Conversion without click_id, coupon_code or customer

policy_acceptance_requiredHTTP 422

No-refund policy acceptance required

Checkout without accept_no_refund_policy: true and a current policy_version

rate_limit_error

rate_limitedHTTP 429

Rate limit exceeded

The single 429 code, always with Retry-After. param tells which limiter: burst (per-plan req/s), daily_quota (plan day quota and packs exhausted), endpoint (per-endpoint, per-IP or publishable-key limit), velocity, exports

api_error

internal_errorHTTP 500

Internal error

Unhandled

upstream_unavailableHTTP 502

Upstream service unavailable

Payment provider / Web Risk / DNS resolver unavailable for a synchronous call

service_unavailableHTTP 503

Service unavailable

Maintenance or dependency outage; a QR render not ready within 8 s

timeoutHTTP 504

Operation timed out

Synchronous operation exceeded 25 s (well under Cloudflare's 100 s)