OpenAPI viewer
JSON over HTTPS, one key per request. Every error says what went wrong, why,
and what would change the outcome.
Scripture is the World English Bible, which is in the public domain.
Billing is metered: search per request, voice search and alignment per
second of audio. GET /v1/usage shows the same figures billing uses.
Make your keys in the developer console at
https://play.fellowverse.app/developers. Every account starts with free
test keys, so you can try everything before anything is billed.
Get started
curl https://play.fellowverse.app/v1/search \
-H "Authorization: Bearer $KEY" -H 'content-type: application/json' \
-d '{"query": "rest for the weary", "limit": 3}'
GET /v1/usage, or under Use in the console.Test keys call the same API as live keys, so the code you write now is the
code you ship.
Keep your key on your server
A key in an Android or iOS app, or in a web page, can be read by anyone who
has the app. Call Fellowverse from your own server and have your app call
your server: it holds the key, decides who may search, and can cache
popular results. Use one key per server or environment, named for it, so
you can replace one without touching the others.
Add voice search to an app
Record the request in the app, send it to your server, and pass the audio
to POST /v1/voice-search as the body with its type. On Android,MediaRecorder with MPEG-4 and AAC gives audio/mp4; in a browser,MediaRecorder gives audio/webm or audio/mp4. Show the transcript
with the results, so people see what was heard; an empty one means nothing
could be heard.
Play a recording verse by verse
POST /v1/uploads) and start an alignmentPOST /v1/alignments). For a Bible reading, leave out segments and
the passage and its verses are found for you.
GET /v1/jobs/{id} every few seconds until it is done or failed.startMs andendMs let your player seek to a verse; words times each word.
clips, download them with your key and host themAlign each recording once, when it is published, and serve the timings
from your own storage, so listeners never wait on an alignment.
Handle errors and limits
Every error has a stable code to branch on, and problem, reason andfix written to be read. Fix a 400 before sending it again. Retry a429 after a short wait (for api_test_quota, fix says when the day's
allowance resets) and a 5xx after a wait that doubles each time.
Searches are safe to retry; before retrying POST /v1/alignments after a
timeout, check whether the first request made a job. A failed job'serror.code says why it failed, such as api_text_mismatch orapi_passage_unknown, and it fails at once rather than being retried.
Go live
Every live key made, rolled or revoked is emailed to the account's owners,
and the console's Activity shows who did what and when.
Authentication
apiKey
Type: HTTP bearer
Send your key as `Authorization: Bearer fv_live_...`. A key is shown once, when it is made. Keep it on your server, not in a web page or an app. Lost keys are revoked and replaced, not recovered. Test keys (`fv_test_...`) call the same API for free, with a daily allowance per account and alignments of up to 10 minutes. Rolling a key replaces it and lets the old one keep working for up to a week while you switch over.
Search
Passages by meaning or by reference, typed or spoken.
/v1/searchSearch by words or a reference
Takes a few words, a feeling or a reference, and returns passages of two
to six verses each, with a context line saying where they sit and who is
speaking.
A reference such as "Psalm 23" or "John 3:16" returns that passage and the
rest of its chapter, with kind set to reference. Anything else is a
search by meaning and wording, with kind set to search.
Billed per request. Limited to 120 a minute per key.
Request Body
Content-Type: application/json
{
"query": "something for fear",
"limit": 5
}Responses
{
"error": {
"code": "bad_request",
"problem": "The recording is 41 seconds long.",
"reason": "Voice search takes a spoken request of up to 30 seconds.",
"fix": "Send a shorter recording; for long audio use alignment."
}
}{
"error": {
"code": "api_unauthorized",
"problem": "The API key was not accepted.",
"reason": "This key was revoked.",
"fix": "Make a new key and use that instead."
}
}{
"error": {
"code": "api_rate_limited",
"problem": "Too many search requests in a minute for this key.",
"reason": "Each key may make 120 a minute.",
"fix": "Wait a moment, or ask Fellowverse for a higher limit."
}
}/v1/voice-searchSearch by a spoken request
Takes a spoken request of up to 30 seconds and 10 MB as the request
body, with its type, and returns what was heard and the same results as a search. The
audio is not kept.
When nothing could be heard, the response holds an empty transcript
and no results.
Billed per second of audio, at least one second. Limited to 60 a minute
per key.
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
limit | query | integer | How many passages to return. |
Request Body
Content-Type: audio/mpeg
The recording itself as the body, with its type in Content-Type. MP3, WAV, M4A, OGG, WebM and FLAC are read.
Responses
{
"error": {
"code": "bad_request",
"problem": "The recording is 41 seconds long.",
"reason": "Voice search takes a spoken request of up to 30 seconds.",
"fix": "Send a shorter recording; for long audio use alignment."
}
}{
"error": {
"code": "api_unauthorized",
"problem": "The API key was not accepted.",
"reason": "This key was revoked.",
"fix": "Make a new key and use that instead."
}
}{
"error": {
"code": "api_rate_limited",
"problem": "Too many search requests in a minute for this key.",
"reason": "Each key may make 120 a minute.",
"fix": "Wait a moment, or ask Fellowverse for a higher limit."
}
}Alignment
When each section and word of a text is spoken in a recording.
/v1/uploadsUpload a recording to align
Takes a recording of up to 200 MB as the request body, with its type.
One alignment takes up to an hour of audio, or 10 minutes with a test key.
Uploads are kept for 7 days (a day with a test key), long enough to align
them; this is not a storage service.
Limited to 30 a minute per key.
Request Body
Content-Type: audio/mpeg
The recording itself as the body, with its type in Content-Type. MP3, WAV, M4A, OGG, WebM and FLAC are read.
Responses
{
"error": {
"code": "bad_request",
"problem": "The recording is 41 seconds long.",
"reason": "Voice search takes a spoken request of up to 30 seconds.",
"fix": "Send a shorter recording; for long audio use alignment."
}
}{
"error": {
"code": "api_unauthorized",
"problem": "The API key was not accepted.",
"reason": "This key was revoked.",
"fix": "Make a new key and use that instead."
}
}{
"error": {
"code": "api_rate_limited",
"problem": "Too many search requests in a minute for this key.",
"reason": "Each key may make 120 a minute.",
"fix": "Wait a moment, or ask Fellowverse for a higher limit."
}
}/v1/alignmentsAlign an upload to the text it reads
Starts aligning an upload to its text, given as sections with your own
ids: paragraphs, sentences, verses or lines. The job runs in the
background; poll GET /v1/jobs/{id} for the result.
Announcements and closing lines set apart by a pause are found and left
out of the sections. Wording that differs slightly from your text is
tolerated.
Leave out segments for a Bible reading: the passage is identified from
what is said, from any verse to any verse and across chapters, and its
verses become the sections. The result then holds passage. A recording
that is not a reading, or only quotes a verse, fails with the codeapi_passage_unknown. Only the World English Bible is held, so a reading
of another translation is found only when enough of its wording agrees.
Billed per second of audio when the job is done. Limited to 30 a minute
per key.
Request Body
Content-Type: application/json
Responses
{
"error": {
"code": "bad_request",
"problem": "The recording is 41 seconds long.",
"reason": "Voice search takes a spoken request of up to 30 seconds.",
"fix": "Send a shorter recording; for long audio use alignment."
}
}{
"error": {
"code": "api_unauthorized",
"problem": "The API key was not accepted.",
"reason": "This key was revoked.",
"fix": "Make a new key and use that instead."
}
}{
"error": {
"code": "api_rate_limited",
"problem": "Too many search requests in a minute for this key.",
"reason": "Each key may make 120 a minute.",
"fix": "Wait a moment, or ask Fellowverse for a higher limit."
}
}/v1/jobs/{id}See a job's state and result
Poll until status is done or failed. A done job holds itsresult; a failed one holds its error.
A job that fails for a reason in the request (an unreadable file, text
that does not match) fails at once with that reason. One that fails on
our side is tried again, up to three times, and goes back to queued
in between. Jobs of a suspended account wait in queued until it is
restored.
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
id* | path | string | The job id returned when the alignment was started. |
Responses
{
"error": {
"code": "api_unauthorized",
"problem": "The API key was not accepted.",
"reason": "This key was revoked.",
"fix": "Make a new key and use that instead."
}
}/v1/jobs/{id}/files/{name}Fetch a clip an alignment made
Clips exist only for alignments made with clips set to true, once the
job is done. Their names are given in the result, one per section. Clips
are kept for 7 days after the job finishes (a day with a test key); then
this returns 404 with
the code api_file_expired.
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
id* | path | string | The job id returned when the alignment was started. |
name* | path | string | The clip's name from the job result, such as `1.mp3`. |
Responses
{
"error": {
"code": "bad_request",
"problem": "The recording is 41 seconds long.",
"reason": "Voice search takes a spoken request of up to 30 seconds.",
"fix": "Send a shorter recording; for long audio use alignment."
}
}{
"error": {
"code": "api_unauthorized",
"problem": "The API key was not accepted.",
"reason": "This key was revoked.",
"fix": "Make a new key and use that instead."
}
}Account
Metered use, as billed.
/v1/usageSee metered use over a period
Returns your use by product, as billed. Without dates it covers the
current month, in UTC, to now. Called with a test key, it returns the
account's test use instead.
Parameters
| Name | Location | Type | Description |
|---|---|---|---|
from | query | string | The start of the period, included. An ISO date or time. |
to | query | string | The end of the period, left out. An ISO date or time. Now when not given. |
Responses
{
"error": {
"code": "bad_request",
"problem": "The recording is 41 seconds long.",
"reason": "Voice search takes a spoken request of up to 30 seconds.",
"fix": "Send a shorter recording; for long audio use alignment."
}
}{
"error": {
"code": "api_unauthorized",
"problem": "The API key was not accepted.",
"reason": "This key was revoked.",
"fix": "Make a new key and use that instead."
}
}