Docs · Start here
Quickstart
Create a key, add a teaching, wait for it to process, read the transcript and note, ask a question and receive a webhook.
This walks one recording from upload to a cited answer. It takes about ten minutes, most of it waiting for processing.
1. Create a key#
In the Folio console open Developers, then API keys, and create a key. Choose the scopes you need. For this walk-through select Full access, or pick media:upload, teachings:read, notes:read, ask:create, ask:read and webhooks:write. Creating a key asks you to sign in again. The secret is shown once; copy it now.
export FOLIO_API_URL="https://your-api-host.example"
export FOLIO_API_KEY="folio_live_xxxxxxxxxxxxxxxxxxxxxxxx"Check the key works by reading the church's plan and usage:
curl -X GET "$FOLIO_API_URL/v1/billing" \
-H "Authorization: Bearer $FOLIO_API_KEY"{
"status": true,
"message": "billing",
"data": { "object": "billing", "standing": { "state": "active" }, "cycle": { "start": "2026-11-01T00:00:00Z", "end": "2026-12-01T00:00:00Z" } }
}A 401 means the key is wrong or expired. A 403 means the key lacks billing:read; try another call or add the scope.
2. Add a teaching#
Creating a teaching returns a signed upload URL. Send an Idempotency-Key so a retry does not create a second teaching.
curl -X POST "$FOLIO_API_URL/v1/teachings" \
-H "Authorization: Bearer $FOLIO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: sunday-2026-11-01-create" \
-d '{
"title": "Sunday, 1 November: Nothing can separate us",
"filename": "sunday.mp3",
"content_type": "audio/mpeg"
}'{
"status": true,
"message": "upload ready",
"data": {
"object": "upload",
"teaching": { "id": "tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012", "object": "teaching", "name": "Sunday, 1 November: Nothing can separate us" },
"key": "originals/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/sunday.mp3",
"url": "https://files.example.org/originals/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/sunday.mp3?X-Signature=abc123",
"expires_at": "2026-11-01T10:15:00Z"
}
}Upload the recording to data.url with a plain PUT and the same content type. No Folio key goes on this request; the URL is signed.
curl -X PUT "$UPLOAD_URL" -H "Content-Type: audio/mpeg" --data-binary @sunday.mp3Then tell Folio the file is there, using the key from the first response:
curl -X POST "$FOLIO_API_URL/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/upload" \
-H "Authorization: Bearer $FOLIO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: sunday-2026-11-01-complete" \
-d '{
"key": "originals/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9099/0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/sunday.mp3"
}'3. Wait for processing#
Processing is asynchronous. Poll the teaching until status is ready or failed. Every few seconds is fine; a long recording takes a few minutes.
curl -X GET "$FOLIO_API_URL/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012" \
-H "Authorization: Bearer $FOLIO_API_KEY"{
"status": true,
"message": "teaching",
"data": { "id": "tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012", "object": "teaching", "status": "processing", "note_status": "none", "duration_seconds": 2412 }
}The statuses are awaiting_upload, queued, processing, ready and failed. When it is failed, failure_reason says why in plain words. Rather than polling you can subscribe to teaching.ready (step 6).
4. Read the transcript#
curl -X GET "$FOLIO_API_URL/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/transcript" \
-H "Authorization: Bearer $FOLIO_API_KEY"{
"status": true,
"message": "segments",
"data": [
{ "object": "segment", "start_ms": 0, "end_ms": 6400, "speaker": "Speaker 1", "text": "Good morning, church. Open your Bibles to Romans chapter eight." }
]
}Asking for the transcript before the teaching is ready answers 404 with a message that says so.
5. Read the note#
Folio writes a note from the transcript, then a person (or the church's automatic approval) reviews it. Until it is published, the call answers 404. That is expected. It is the review step working.
curl -X GET "$FOLIO_API_URL/v1/teachings/tch_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/note" \
-H "Authorization: Bearer $FOLIO_API_KEY"{
"status": true,
"message": "note",
"data": {
"id": "note_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012",
"object": "note",
"status": "published",
"summary": "Nothing in all creation can separate us from the love of God in Christ.",
"sections": [{ "h": "Who can condemn?", "body": "Paul answers with Christ's death, resurrection and intercession." }]
}
}6. Ask a question#
Answers are written from the church's approved teaching and cite their sources. The answer is asynchronous: the first response holds a pending answer.
curl -X POST "$FOLIO_API_URL/v1/conversations" \
-H "Authorization: Bearer $FOLIO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: faq-forgiveness-1" \
-d '{
"title": "Forgiveness",
"input": "What did we teach about forgiveness?"
}'Poll the conversation until the last message's kind is no longer pending:
curl -X GET "$FOLIO_API_URL/v1/conversations/conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012" \
-H "Authorization: Bearer $FOLIO_API_KEY"{
"status": true,
"message": "conversation",
"data": {
"id": "conv_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012",
"messages": [
{ "role": "user", "kind": "question", "text": "What did we teach about forgiveness?" },
{ "role": "assistant", "kind": "answer", "short_answer": "Forgiveness is a decision to release a debt, as God released ours. [1]", "sources": [{ "number": 1, "title": "Seventy times seven", "speaker": "Pastor Ade" }] }
]
}
}If the church has not taught on the subject the answer has kind not_covered. That is the honest answer, not an error.
7. Hear about it by webhook#
Register an https endpoint and subscribe it to the events you care about. The signing secret is returned once.
curl -X POST "$FOLIO_API_URL/v1/webhook-endpoints" \
-H "Authorization: Bearer $FOLIO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: endpoint-sunday-pipeline" \
-d '{
"name": "Sunday pipeline",
"url": "https://hooks.example.org/folio",
"event_types": [
"teaching.ready",
"note.published"
],
"mode": "live"
}'Check your receiver with a signed test event, then read webhooks to verify signatures in your own code:
curl -X POST "$FOLIO_API_URL/v1/webhook-endpoints/whe_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/test" \
-H "Authorization: Bearer $FOLIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"event_type": "note.published"
}'Where next#
- Authentication and scopes to give each key only what it needs.
- Errors for every code and what to do about it.
- Going to production before you point a live church at your code.
Verified against API version 0.0.0-dev. Generated from the live OpenAPI document.