YouVersion PlatformYouVersion Platform
PlatformBiblesDev Docs
CommunityPartnersSupport

YouVersion Platform

Build applications and integrate with the world's most popular Bible platform.

Platform Products

  • Platform Portal
  • Developer Documentation
  • App Management

Resources

  • Support
  • Press inquiries

Legal

  • Privacy Policy
  • Terms of Use

© 2026 YouVersion. All rights reserved.

  • Overview
  • API Reference
  • SDKs
  • Changelog
<  Back to Platform
Getting Started
    YouVersion Platform OverviewAPI Usage
Guides
    Display Bible HTMLSign-in APIsSearch APIsUSFM ReferenceError Codes
Useful Links
    YouVersionGitHub
Guides

Error Codes

The YouVersion Bible API uses standard HTTP status codes to indicate the success or failure of requests. This page documents the status codes the API returns, the response body shape you get with each, and how to handle them.

Status code definitions link to RFC 9110, the HTTP Semantics specification, and are registered in the IANA HTTP Status Code Registry.

HTTP Status Codes

2xx Success

CodeMeaningWhen you see it
200 OKRequest succeededStandard successful response
201 CreatedResource createdAfter a successful POST, for example creating a highlight
204 No ContentSucceeded, nothing to returnNo data matches your parameters. This is not an error
206 Partial ContentPart of the resourceYou sent a Range header. Responses advertise Accept-Ranges: bytes

3xx Redirection

CodeMeaningWhen you see it
301 Moved PermanentlyResource has a canonical URLA non-canonical language code redirects to its canonical form, e.g. /v1/languages/cmn to /v1/languages/zh. Follow the Location header
303 See OtherContinue at another URLThe consent redirect back to your callback URL. See Sign In APIs
304 Not ModifiedYour cached copy is currentYou sent If-None-Match or If-Modified-Since and nothing changed. The body is empty, so reuse what you have
308 Permanent RedirectResource has a new URLPlain HTTP is redirected to HTTPS. Follow the Location header

4xx Client Errors

CodeMeaningWhen you see it
400 Bad RequestInvalid parameters or request formatA parameter value the API cannot accept
401 UnauthorizedMissing or invalid App KeyNo X-YVP-App-Key header, or the key is not recognized
403 ForbiddenKey is valid but not permittedYour App Key cannot access this content or endpoint
404 Not FoundResource does not existUnknown Bible, book, chapter, or verse
405 Method Not AllowedWrong method for this pathThe path exists but not for that verb, for example POST /v1/bibles. OPTIONS is also unsupported, so browser preflights fail
409 ConflictThe resource already existsCreating a highlight the user already has. Treat it as success
412 Precondition FailedThe app behind your App Key is archived or unknownThe key still authenticates, but the app it belongs to has been archived or removed. Check the app's status in the Developer Portal
422 Unprocessable ContentRequest understood but parameters failed validationA required parameter is missing or malformed
429 Too Many RequestsRate limit exceededYou have exceeded your App Key's request allowance

5xx Server Errors

CodeMeaningWhen you see it
500 Internal Server ErrorUnexpected server errorRetry with backoff
502 Bad GatewayAn upstream service failedRetry with backoff
503 Service UnavailableTemporarily unavailableRetry with backoff
504 Gateway TimeoutAn upstream service did not answer in timeMost often a large passage or catalog request. Retry with backoff

Response Body Shapes

Errors do not all share one body shape, because they can be produced at different layers. Parse defensively rather than assuming a single format.

Most API errors return a JSON object with a message field:

Code
{ "message": "Bible version 99999999 not found" }

Authentication errors are produced at the API gateway before your request reaches the API, and use a fault envelope:

Code
{ "fault": { "faultstring": "Invalid ApiKey", "detail": { "errorcode": "oauth.v2.InvalidApiKey" } } }

Parameter validation errors return a detail array, one entry per invalid parameter:

Code
{ "detail": [ { "type": "missing", "loc": ["query", "query"], "msg": "Field required", "input": null } ] }

Rate limit errors are returned at the edge as text/plain, not JSON:

Code
Rate limit exceeded.

Calling response.json() on a 429 will throw. Check the status code before parsing.

Common Error Scenarios

Authentication Errors

Status Code: 401 Unauthorized

Cause: Missing or invalid X-YVP-App-Key header.

Browser note: today this response is generated at the API gateway, ahead of the application, and does not include Access-Control-* headers, so a browser fetch() rejects with a TypeError rather than exposing response.status. Server-side callers see the 401 normally.

Example Response (header missing entirely):

Code
{ "fault": { "faultstring": "Failed to resolve API Key variable request.header.x-yvp-app-key", "detail": { "errorcode": "steps.oauth.v2.FailedToResolveAPIKey" } } }

Example Response (header present, key not recognized):

Code
{ "fault": { "faultstring": "Invalid ApiKey", "detail": { "errorcode": "oauth.v2.InvalidApiKey" } } }

Solution: Include a valid App Key in the X-YVP-App-Key header with every request. The two errorcode values above distinguish a missing header from an unrecognized key.

Forbidden

Status Code: 403 Forbidden

Cause: Your App Key is valid, but it is not permitted to do what the request asks. This is distinct from a 401, where the key itself is not recognized. There are three common causes:

  • The Bible is not licensed to your app. Each Bible is available only to apps whose organization has accepted the relevant publisher license. Requesting a Bible outside that set is forbidden even though the Bible exists.
  • The endpoint is not enabled for your App Key. Not every App Key is authorized for every API.
  • A required user permission was not granted. Endpoints acting on user data, such as highlights, need the signed-in user to have granted that permission. Without the grant the request is forbidden even with a valid key and token.

Example Response (requesting a passage from a Bible your app is not licensed for):

Code
{ "message": "Access denied for 111" }

The number in the message is the Bible ID that was refused.

Metadata is not gated the same way as content. GET /v1/bibles/{bible_id} returns 200 with the version's title, abbreviation, and copyright even when your app is not licensed for it. Only the content endpoints, such as GET /v1/bibles/{bible_id}/passages/{usfm}, return 403. A Bible appearing in a metadata response is therefore not a guarantee that you can read its text.

Solution: Check which Bibles your key can reach by calling GET /v1/bibles?language_ranges[]=en without all_available, which returns only what your app is licensed for. Compare that against GET /v1/bibles?all_available=true&language_ranges[]=en, which returns the full platform catalog. language_ranges[] is required on both; omitting it returns a 422. If the Bible appears only in the second list, your organization needs to accept that publisher's license. For user data endpoints, confirm the user completed the permission grant during sign in.

A common cause is a hardcoded default Bible ID that your App Key is not licensed for. Prefer selecting a Bible from your app-scoped GET /v1/bibles?language_ranges[]=en response rather than assuming an ID is available.

Invalid Parameters

Status Code: 400 Bad Request

Cause: A parameter value the API cannot accept, such as a language_ranges[] value containing characters outside letters, numbers, hyphens, and *.

Example Response:

Code
{ "message": "Invalid language_range value: '%%%'. Only letters, numbers, hyphens, and wildcards (*) are allowed." }

A parameter of the wrong type, or a required parameter left out, is a 422 rather than a 400. See Failed Validation below.

Failed Validation

Status Code: 422 Unprocessable Content

Cause: The request was well formed, but a parameter failed validation. Most often a required parameter is missing, or a value is outside its allowed range.

Example Response:

Code
{ "detail": [ { "type": "missing", "loc": ["query", "query"], "msg": "Field required", "input": null } ] }

Solution: Read loc to find which parameter failed and msg for the reason. The array contains one entry per failing parameter, so a single response can report several problems at once.

Resource Not Found

Status Code: 404 Not Found

Cause: The requested resource does not exist.

Example Response:

Code
{ "message": "Bible version 99999999 not found" }

Common Scenarios:

  • Bible version ID doesn't exist
  • Book USFM identifier is invalid
  • Chapter number exceeds the book's chapter count
  • Verse number exceeds the chapter's verse count

A 404 can also mean the endpoint path itself is not recognized. If a request returns 404 with an empty body rather than a JSON message, check the URL before checking your parameters.

Rate Limited

Status Code: 429 Too Many Requests

Cause: You have exceeded the request allowance for your App Key. Limits are applied per App Key at the edge.

Response Headers:

  • Retry-After: seconds to wait before retrying

Example Response (Content-Type: text/plain):

Code
Rate limit exceeded.

Solution: Respect the Retry-After header rather than retrying immediately, and use exponential backoff for repeated failures. Because this response is plain text, guard your parsing with a status check before calling response.json().

Browser note: today this response is built at the edge with only Retry-After and a body, so it does not include Access-Control-* headers. A browser fetch() rejects with a TypeError, and neither the status nor Retry-After is readable. Server-side callers see both normally.

To reduce the chance of hitting the limit, cache responses where you can and avoid fanning out one request per Bible version when a single call would do.

No Content Available

Status Code: 204 No Content

Cause: Request was successful but no data matches the criteria.

Example: Requesting Bible versions for a language that has no available translations.

Solution: This is not an error. It is a valid response indicating no content is available for the given parameters. A 204 has no response body, so do not try to parse one.

Error Handling Examples

JavaScript (Fetch API)

The samples below request /v1/bibles?language_ranges[]=en. language_ranges[] is required on that endpoint, so the bare path returns a 422 rather than the success these examples are meant to show.

Code
async function makeApiRequest(url, appKey) { // In a browser, fetch rejects before these branches for responses without CORS // headers; see the Browser notes under 401 and 429 above. const response = await fetch(url, { headers: { 'X-YVP-App-Key': appKey, 'Accept': 'application/json' } }); if (response.status === 204) { return null; // Success, but no content } if (response.status === 429) { // Plain text body. The edge always sets Retry-After on a rate-limited response. const retryAfter = response.headers.get('Retry-After'); throw new Error(`Rate limited. Retry after ${retryAfter}s.`); } if (!response.ok) { // Error bodies vary by layer, so read defensively. const body = await response.json().catch(() => null); const detail = body?.message ?? // most API errors body?.fault?.faultstring ?? // gateway auth errors body?.detail?.[0]?.msg ?? // parameter validation 'Unknown error'; throw new Error(`${response.status}: ${detail}`); } return response.json(); } // Usage try { const bibles = await makeApiRequest('https://api.youversion.com/v1/bibles?language_ranges[]=en', 'YOUR_APP_KEY'); console.log('Bibles:', bibles); } catch (error) { console.error('Failed to fetch bibles:', error.message); }

Python (Requests)

Code
import requests def make_api_request(url, app_key): headers = { 'X-YVP-App-Key': app_key, 'Accept': 'application/json', } response = requests.get(url, headers=headers) if response.status_code == 204: return None # Success, but no content if response.status_code == 429: # Plain text body. The edge always sets Retry-After on a rate-limited response. retry_after = response.headers.get('Retry-After') raise RuntimeError(f'Rate limited. Retry after {retry_after}s.') if not response.ok: # Error bodies vary by layer, so read defensively. try: body = response.json() except ValueError: body = {} detail = ( body.get('message') # most API errors or body.get('fault', {}).get('faultstring') # gateway auth errors or (body.get('detail') or [{}])[0].get('msg') # parameter validation or 'Unknown error' ) raise RuntimeError(f'{response.status_code}: {detail}') return response.json() # Usage bibles = make_api_request('https://api.youversion.com/v1/bibles?language_ranges[]=en', 'YOUR_APP_KEY') if bibles: print('Bibles:', bibles)

cURL

TerminalCode
# No -L: redirects are reported rather than followed, so you can see them. # Headers and body are captured separately so each branch can read what it needs. http_code=$(curl -s -D /tmp/headers -o /tmp/body -w '%{http_code}' \ -H "X-YVP-App-Key: YOUR_APP_KEY" \ https://api.youversion.com/v1/bibles?language_ranges[]=en) location() { grep -i '^location:' /tmp/headers | tr -d '\r' | cut -d' ' -f2-; } retry_after() { grep -i '^retry-after:' /tmp/headers | tr -d '\r' | cut -d' ' -f2-; } case "$http_code" in 204) echo "No content available." ;; 2*) echo "Success: $(cat /tmp/body)" ;; 3*) echo "Redirected to: $(location)" ;; 401) echo "Authentication failed. Check your App Key." ;; 403) echo "Forbidden: $(cat /tmp/body)" ;; 404) echo "Not found: $(cat /tmp/body)" ;; 422) echo "Validation failed: $(cat /tmp/body)" ;; 429) echo "Rate limited. Retry after $(retry_after)s." ;; *) echo "Error: HTTP $http_code"; cat /tmp/body ;; esac

Two things worth copying from this. The 204 case comes before the general 2* case, because it has no body to print. And -L is deliberately absent: with it, curl follows the redirect and %{http_code} reports the final hop, so /v1/languages/cmn would report 200 and you would never see the 301. Add -L once you no longer care about the redirect itself.

The 403 and 404 branches print the body rather than a fixed string, because both codes have more than one cause and only the message distinguishes them.

Best Practices for Error Handling

  1. Always check status codes: Don't assume requests will succeed
  2. Check the status before parsing: 204 has no body and 429 is plain text, so parsing either as JSON will throw
  3. Handle 401 and 403 differently: 401 means the key is not recognized, 403 means it is recognized but not permitted. Retrying with the same key fixes neither
  4. Implement retry logic: For transient errors (5xx) and for 429, honoring Retry-After
  5. Log error details: Include status codes and error messages in logs
  6. Provide user-friendly messages: Translate technical errors for end users
  7. Validate parameters: Check parameters before making requests
  8. Use appropriate timeouts: Don't let requests hang indefinitely

Testing Error Scenarios

You can test error handling by:

  1. Invalid App Key: Use a fake App Key to test 401 responses
  2. Unlicensed Bible: Request a Bible ID that appears in GET /v1/bibles?all_available=true&language_ranges[]=en but not in your app-scoped GET /v1/bibles?language_ranges[]=en to test 403 responses
  3. Invalid Bible ID: Use a non-existent Bible ID (e.g. 99999999) to test 404 responses
  4. Missing required parameter: Omit a required query parameter to test 422 responses
  5. Invalid parameters: Use malformed query parameters to test 400 responses
  6. Network issues: Disconnect from the internet to test connection errors

Getting Help

If you encounter errors that aren't documented here or need clarification:

  1. Check the API Reference for endpoint-specific error information
  2. Review the Authentication guide
  3. Contact the YouVersion Platform Team for support
Last modified on October 2, 2026
USFM Reference
On this page
  • HTTP Status Codes
    • 2xx Success
    • 3xx Redirection
    • 4xx Client Errors
    • 5xx Server Errors
  • Response Body Shapes
  • Common Error Scenarios
    • Authentication Errors
    • Forbidden
    • Invalid Parameters
    • Failed Validation
    • Resource Not Found
    • Rate Limited
    • No Content Available
  • Error Handling Examples
    • JavaScript (Fetch API)
    • Python (Requests)
    • cURL
  • Best Practices for Error Handling
  • Testing Error Scenarios
  • Getting Help
JSON
JSON
JSON
JSON
JSON
JSON
JSON
JSON
JSON
Javascript